Автоматическое определение микросхем I2C EEPROM Печать
Добавил(а) microsin   

В этой статье (перевод апноута AN690 Microchip [1]) описывается метод автоматического определения размера памяти EEPROM с последовательным интерфейсом I2C. Рассматриваются темы:

• Автоопределение размера памяти, подключенной к шине I2C
• Стандарт I2C
• Smart Serial или I2C?
• Набор подпрограмм для I2C
• Как распознать схему адресации
• Как распознать размер
• Как собрать все вместе
• Отладка
• Совместимость
• Ссылки

[Автоопределение размера памяти, подключенной к шине I2C]

В приложениях с микроконтроллерами, где используется память Serial EEPROM, часто встает проблема согласования требований приложения и оптимизации стоимости используемых компонентов. Пользователю часто нужно использовать разные размеры памяти для разных версий приложения, однако ценовые ограничения требуют использовать каждый раз минимальный размер памяти. Примером типового приложения может быть базовая станция (приемник) дистанционно управляемой системы открытия двери гаража. Версии, которые могут хранить в памяти 4, 20, 200 или 1000 пользователей, могли бы с одним и тем же исходным кодом, подходящим к различным используемым микросхемам памяти.

Microchip поставляет широкий диапазон емкости памяти с интерфейсом I2C (от 16 байт в 24C00 до 32k байт 24C256). У микроконтроллера должен быть способ определить, какая память используется на шине I2C, чтобы можно было правильно её адресовать.

Для решения этой проблемы есть 2 возможных метода - один состоит в предоставлении какой-либо конфигурационной информации для контроллера, например с помощью DIP-переключателей или перемычек, и другой способ подразумевает автоматическое определение конфигурации памяти. В этом апноуте показано, как просто и безопасно реализовать автоматическое детектирование подключенной памяти.

Описанные программные техники демонстрируются на обычном микроконтроллере PIC16C62A среднего ценового диапазона, и это может быть немедленно протестировано на демо-плате PICDEM2. Весь код может быть адаптирован для других микроконтроллеров семейства PICmicro (с ядрами 12, 14, 16 и/или другими конфигурациями выводов) путем незначительных изменений в исходном коде.

[Стандарт I2C]

Протокол I2C использует двунаправленную шину, работающую по принципу главного устройства и подключенных к нему подчиненных устройств (схема master/slave). Главное устройство (master) это обычно микроконтроллер, который управляет шиной, генерирует такты (SCL) и формирует сигналы START и STOP на шине. Serial EEPROM ведет себя как подчиненное (slave) устройство, и оно работает как передатчик данных во время операций чтения. Во время операций записи EEPROM работает как приемник, формируя сигналы положительного и отрицательного подтверждения (ACK и NACK) для устройства master. Сигналы START и STOP используются для управления потоком данных по шине. Нормальная операция начинается с сигнала START и заканчивается сигналом STOP. За START начинается команда чтения или записи, содержащая адрес устройства, эту команду формирует master. Этот первый байт называется байтом управления, он идентифицирует подчиненное устройство и определяет следующую операцию - чтение это будет или запись. Типовой байт управления для Serial EEPROM показан на рис. 1. Таким образом, байт управления начинается с сигнала START, за которым идет 4-битный идентификатор типа устройства (для устройства типа EEPROM это будут биты 1010), затем 3 бита, выбирающие конкретную микросхему на шине I2C (A2, A1, A0), бит чтения/записи (R/W), за которым должно идти подтверждение от slave-устройства (ACK).

AN690 Control Byte Allocation fig01

Рис. 1. Структура байта управления.

[Smart Serial или I2C?]

Последовательная шина I2C имеет много преимуществ перед другими последовательными шинами для встраиваемых устройств. Шина I2C с триггерами Шмитта на входах, срабатывающих по уровню, дает лучшую помехозащищенность по сравнению с технологиями, которые основаны на перепадах уровня. Для обмена с микросхемами памяти не требуются коды операций и используют интуитивно-понятную схему операций.

Однако стандартный протокол ограничивает адресацию памяти максимумом 16K байт при использовании 8-битного адреса и трех выводов A0, A1 и A2 (8 x 2 килобайта). Здесь заключается некая дилемма. С появлением более современных персональных устройств связи, таких как сотовые телефоны, наладонники и другие переносные устройства, 16K байт будет недостаточно.

Поэтому в связи с требованиями индустрии к повышению размеров памяти I2C во встраиваемых приложениях появилась концепция Smart Serial, удовлетворяющая требованиям уменьшения износа памяти, повышения безопасности данных. Также с этой концепцией была добавлена функциональность поддержки пониженного потребления энергии.

Компанией Microchip была разработана схема адресации для I2C Serial EEPROM, основанная на стандартном протоколе I2C и адресе устройства, но был введен дополнительный байт адреса, чтобы позволить разработчику применить до 256K бит на устройство и добавить от 1 до 8 устройств на одну системную шину I2C. Это позволило будущее расширение памяти, и дало продвинутые возможности в маленьких, эффективных по стоимости разработках.

Для первого байта, или управляющего байта, Smart Serial придерживаются стандартного протокола I2C (см. рис. 2). Следующие 2 байта (вместо одного) определяют адрес запрашиваемой области памяти.

AN690 Byte Write fig02

Рис. 2. Запись байта.

[Другой набор подпрограмм для шины I2C]

Компанией Microchip Technology было опубликовано множество апноутов с интерфейсом к шине I2C: AN515, AN537, AN558, AN567, AN608, AN554, AN578 и AN535. Ниже будут будут использованы техники из этих даташитов, и на основе их кода будут создан компактный, мощный набор подпрограмм. Сначала будет модифицирован базовый набор подпрограмм [3, 4, 6, 8, 10], чтобы они поддерживали адресацию Standard I2C и Smart Serial, выбирали runtime схему адресации посредством флага SMART.

Листинг 1 (i2c.inc) показывает новый набор подпрограмм. Как обычно, здесь присутствует 2 слоя функций:

• Нижний слой (состоящий из подпрограмм: BSTOP, BSTART, RXI2C, TXI2C, BITIN, BITOUT, ERR), который реализует отправку и определение одиночных бит и байтов на шине, и на этом слое нет нового кода.

• Верхний слой (состоящий из подпрограмм: RDbyte, WRbyte и SETI2C), который обрабатывает команды и заботится о схемах адресации. В этой документации в основном обсуждается именно этот слой.

Нововведение здесь следующее: в функцию SETI2C перенесен весь код, который работает с деталями схемы адресации. Эта функция получает флаг SMART на входе, и предоставляет адресацию Standard или Smart в соответствии с его значением. Функции RDbyte и WRbyte полагаются на SETI2C для генерации команды и адреса, чтобы добиться совместимости со Standard и Smart Serial.

[Определение схемы адресации]

Следующий небольшой шаг к автоматическому определению размера памяти - нам нужно найти метод, чтобы автоматически отличить Smart Serial и Standard Serial EEPROM. Предлагается простой и компактный алгоритм, состоящий из 4 шагов:

1. Перевод I2C подпрограмм в режим Smart Serial (установкой флага SMART).

2. Выдается команда write в ячейку 0000, с записью 1.

Если память стандартная I2C, то эта команда интерпретируется как команда последовательной записи (sequential write) двух байт, в результате запишется байт 00 в ячейку 0000 и байт 01 в ячейку 0001. Если же память Smart Serial, то мы получим корректную интерпретацию адреса, и в ячейку 0000 будет записан байт 01.

3. Подпрограммы I2C переводятся в стандартный режим (Standard I2C Mode, путем очистки флага SMART).

4. Выдается команда read ячейки 0000.

Если память действительно Standard I2C, то эта команда read даст нам содержимое ячейки 0000, которая была установлена в 0. Если же память типа Smart Serial, то получится команда чтения с частичной (неполной) адресации. То, что произойдет, не относится непосредственно к работе шины I2C, давайте проанализируем эти два возможных случая.

a) Частичная адресация только установит старшие значащие биты внутреннего регистра адреса, и оставит не измененными младшие 8 бит. Это означает, что будет прочитана ячейка 0000.
b) Частичная адресация не модифицирует весь регистр адреса. Это означает, что адрес остается равным последнему установленному значению (последней операцией Smart Write), и чтение даст содержимое ячейки 0000.

Если в обоих случаях процесс завершится чтением 1, то это укажет нам на память Smart Serial. Если будет прочитан 0, то это последовательная память Standard I2C.

Листинг 2 (i2cauto.asm) реализует этот простой алгоритм на 10 строках ассемблера.

Замечание: очевидно, что описанная процедура повредит содержимое ячеек 0000 и 0001, и не существует способа сохранить и восстановить их (пока не будет определена схема адресации!).

[Определение размера памяти]

Последний шаг к автоматическому определению размера памяти - разработка алгоритма, который определит размер памяти по имеющейся схеме адресации. Предположим, что уже известен тип памяти - Standard или Smart, и необходимо определить её размер.

Детектирующий алгоритм будет базироваться на простом предположении: если память имеет размер N, то попытка адресации вне диапазона 0..N-1 приведет к попаданию обратно в этот диапазон. Поскольку самые старшие (дополнительные) биты адреса будут просто игнорироваться, для устройства они не будут иметь значения. Это можно просто проверить по даташиту каждой микросхемы памяти.

Можно разработать простую тест-функцию, которая скажет нам, имеет ли память размер N, или у неё размер меньше. На псевдокоде эта функция будет выглядеть примерно так:

bool TestIfSizeIs (u32 N)
{
   // Адреса памяти находятся в диапазоне 0..N-1?
   u8 TEMP;
   TEMP = Read(0000);
   if (Read(N) == TEMP)
   {
      Write(0000, TEMP+1);
      if (Read(N) == TEMP+1)
      {
         Write(0,TEMP-1);
         return TRUE;
      }
   }
   // Иначе:
   return(FALSE)
}

С помощью такой функции мы можем организовать цикл проверки размеров памяти. В случае памяти Standard I2C цикл может проверять от N=128 до N=2048 (микросхемы от 24C01 до 24C16) удваивая N на каждой итерации:

u8 StandardI2CMemDetect (void)
{
   // Функция вернет номер модели микросхемы памяти 1..16.
   u16 N = 128;
   u8 MODEL = 1;
   do
   {
      if (TestIfSizeIs(N))
         break;
      else
      {
         N=N*2;
         MODEL=MODEL*2;
      }
   }
   while(N <= 2048);
   return MODEL;
}

Подобным образом функция может проанализировать память Smart Serial в диапазоне от N=4096 до N=32768.

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

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

Листинг 2 (i2cauto.asm) реализуют на ассемблере оба алгоритма (определение схемы адресации и размера).

Код может быть протестирован на PIC16C62A (плата PICDEM2) или любой другой целевой системе (после модификации используемых ножек выводов листинга 2 i2cauto.asm). После установки памяти I2C в сокет DIL платы PICDEM2, подайте на неё питание или нажмите кнопку сброса, и светодиоды покажут в двоичном представлении значение TYPE (см. таблицу 1).

Таблица 1. Значение TYPE для разных микросхем памяти.

Standard I2C Smart Serial
TYPE Размер Модель TYPE Размер Модель
01 128 24C01
24C21
24C41
32 4096 24C32
02 256 24C02
24C62
64 8192 24C64
24C65
04 512 24C04 128 16384 24C128
08 1024 24C08 0 32768 24C256
16 2048 24C16
24C164
     

Вы можете экспериментировать и изменить предлагаемый код (см. ниже врезку "Приложение A: код ассемблера для PIC16C62A"), чтобы он соответствовал Вашим определенным требованиям. Однако старайтесь учитывать допустимое количество перезаписей (ограниченный ресурс) микросхем EEPROM, и используйте программную утилиту "Endurance" от Microchip Technology, когда разрабатываете приложения с особыми требованиями к надежности [11, 12].

[Совместимость]

Почти весь представленный код строго следует существующим стандартам I2C и Smart Serial, поэтому он должен быть совместим с любым устройством Serial EEPROM от любого производителя, который придерживается этих стандартов. Однако код проверялся только с микросхемами Microchip Serial EEPROM, и пользователь должен самостоятельно обеспечить совместимость кода с микросхемами памяти от других производителей.

Кроме того, возможны некоторые проблемы совместимости на шаге детектирования схемы адресации. Фактически поведение последовательной памяти в случае частичной адресации (что происходит на шаге 4 в случае Smart Serial) не является частью спецификации. Несмотря на то, что с текущей реализации протокола Smart Serial предлагаемое решение работает нормально (с микросхемами Microchip вплоть до 24C256), не гарантируется, что это также хорошо будет работать и в будущем.

[Листинг 1: I2C.INC]

;**********************************************************************
;* Файл: I2C.INC
;**********************************************************************
;* Автор: Lucio Di Jasio
;* Компания: Microchip Technology
;* Ревизия: RevA0
;* Дата: 5-7-98
;* Ассемблировано с помощью MPASM v02.15
;**********************************************************************
;* Примеры подпрограмм READ/WRITE шины I2C/TWI для обоих
;* поддерживаемых схем адресации Smart Serial и Standard I2C.
;* Версия PIC16CXXX mid-range (ядро 14 бит)
;* Примечания:
;* 1) Все тайминги основаны на кварце 4 МГц с соответствующим
;*    временем инструкции 1 мкс.
;* 2) Адреса и литеральные значения даны в HEX-форме, если не указано
;*    что-то другое.
;*****************************************************************************
;* Назначение файла регистров
;*****************************************************************************
CBLOCK
   FLAGS
   INDHI       ; адрес
   INDLO
   DATO        ; буфер данных для функций чтения и записи
   ERCODE      ; код ошибки (см. таблицу ниже)
   EEBUF       ; буфер чтения/записи
   SLAVEbuf    ; SLAVE-адрсе (+ addrHi на 24LC16)
   COUNT
   AUX
ENDC
;**********************************************************************
; Определения флагов;
#define FLAG_EE FLAGS,0    ; ошибки шины I2C
#define SMART FLAGS,1      ; Smart(1) Standard(0)
;
;*****************************************************************************
;* Назначение бит
;*****************************************************************************
#define SLAVE B'10100000'  ; Адрес устройства (1010xxx0); коды ошибок
#define ERR_NACK 1         ; не прочитан ACK
#define ERR_STOP 2         ; SDA заблокирован на STOP
#define ERR_TOWR 3         ; таймаут чтения (> 20 мс)
#define ERR_LOCK 4         ; SDA заблокирован в BITOUT
 
;*****************************************************************************
;* RDbyte
;* Чтение одного байта из устройства памяти serial EEPROM
;*
;* Вход:    INDHI/LO
;*          SLAVE = адрес устройства (1010xxx0)
;* Выход:   DATO = данные, прочитанные из serial EEPROM
;*****************************************************************************
RDbyte   bcf FLAG_EE       ; сброс флага ошибки
         call SETI2C       ; установка указателя адреса
; вход в последовательное чтение (sequential reading)
RDnext   call BSTART       ; START
         movf SLAVEbuf,W   ; используется SLAVE addr(+IndHi при 24LC16)
         movwf EEBUF
         bsf EEBUF,0       ; команда чтения
         call TXI2C        ; вывод SLAVE + address + команда read
         call RXI2C        ; чтение в DATO и ACKnowledge
         movf EEBUF,W
         movwf DATO
         bsf STATUS,C      ; ACK = 1 (NOT ACK)
         call BITOUT       ; для остановки ввода (STOP)
         goto BSTOP        ; генерация STOP-бита
 
;*****************************************************************************
;* WRbyte
;* Запись одного байта в устройство EEPROM
;*
;* Вход:    DATO     = записываемые данные
;*          INDHI/LO = адрес EEPROM
;*          SLAVE    = адрес устройства (1010xxx0)
;*          PROT     = 1 SmartSerial | 0 Standard
;* Выход:   FLAG_EE  = установится, если операция завершилась неудачно
;*****************************************************************************
WRbyte   bcf FLAG_EE       ; сброс флага ошибки
         call SETI2C       ; установка указателя адреса
         movf DATO,W       ; перемещение DATO
         movwf EEBUF       ; в буфер
         call TXI2C        ; вывод DATO и детектирование ACKnowledge
         call BSTOP        ; генерация STOP-бита; цикл ожидания завершения записи
         movlw .80         ; 80 = таймаут 20 мс
         movwf AUX
WRpoll   CLRWDT            ; сброс сторожевого таймера
         bcf FLAG_EE
         call BSTART       ; старт
         movlw SLAVE
         movwf EEBUF
         call TXI2C        ; и команда записи
         btfss FLAG_EE     ; если не ACK -> код ошибки 3 -> BUSY
         goto WRpollE
 
WRbusy   decfsz AUX,F
         goto WRpoll
         movlw ERR_TOWR    ; таймаут записи
         call ERR
WRpollE  goto BSTOP        ; выход с отправкой сигнала STOP
 
;*****************************************************************************
;* SETI2C
;* Устанавливает указатель адреса на INDHI/LO, используется схема
;* адресации Smart или Standard, в зависимости от флага SMART.
;*
;* Вход:       INDHI = адрес EEPROM
;*             INDLO
;*             SLAVE = адрес устройства (1010xxx0)
;*             SMART = 1 Smart Serial | 0 Standard I2C
;* Выход:      SLAVEbuf для sequential read
;*****************************************************************************
SETI2C
         btfsc SMART       ; если 0, то Standard I2C
         goto Smart        ; если 1, то Smart Serial
 
Standard
         bcf STATUS,C      ;
         rlf INDHI,W       ; добавление к slave-адресу
         iorlw SLAVE       ; старших бит адреса
         movwf EEBUF
         movwf SLAVEbuf    ; сохранение для sequential read
         call BSTART       ; генерация START-бита
         call TXI2C        ; вывод первого байта команды
         goto SETseq
 
Smart
         movlw SLAVE       ; подготовка slave-адреса
         movwf EEBUF
         movwf SLAVEbuf    ; сохранение для sequential read
         call BSTART       ; генерация START-бита
         call TXI2C        ; вывод первого байта команды
         movf INDHI,W      ;
         movwf EEBUF       ; вывод старшего байта адреса
         call TXI2C
SETseq
         movf INDLO,W      ; отправка младшего байта адреса
         movwf EEBUF
         goto TXI2C        ; вывод адреса слова
 
;*****************************************************************************
;* TXI2C
;* Передает 8 бит данных
;*;* Вход:    EEBUF
;* Выход:   нет
;*****************************************************************************
TXI2C
         movlw .8 ; Set counter for eight bits
         movwf COUNT
TXlp
         rlf EEBUF,F    ; бит данных находится в CARRY
         call BITOUT    ; отправка бита
         decfsz COUNT,F ; отправлено 8 бит?
         goto TXlp      ; нет...
         call BITIN     ; чтение бита ACK
         movlw ERR_NACK
         btfsc STATUS,C ; проверка подтверждения
         call ERR       ; нет подтверждения от устройства
         return
 
;*****************************************************************************
;* BITOUT
;* Отправка одного бита
;*
;* Вход:    бит в флаге переноса CARRY
;* Выход:   бит передается по шине I2C
;* Если необходимо, то установятся биты ошибки.
;*****************************************************************************
BITOUT
         btfss STATUS,C ; 0 или 1?
         goto Bit0
 
Bit1
         bsf STATUS,RP0 ; выбор RAM bank 1
         bsf SDA        ; вход SDA (pull up -> 1)
         bcf STATUS,RP0 ; обратно в RAM bank 0
         movlw ERR_LOCK
         btfss SDA      ; Проверка на ошибку
         call ERR       ; SDA заблокирован микросхемой памяти
         goto Clk1
 
Bit0
         bsf STATUS,RP0 ; выбор RAM bank 1
         bcf SDA        ; выход SDA
         bcf STATUS,RP0 ; обратно в RAM bank 0
         bcf SDA        ; сброс в 0
         nop            ; задержка
Clk1
         bsf SCL        ; перевод SCL в лог. 1
         nop
         nop
         nop            ; задержка минимум 4 мкс
         nop
         nop
         bcf SCL        ; перевод SCL в лог. 0
         return
 
;*****************************************************************************
;* RXI2C
;* Прием 8 бит данных
;*
;* Вход:       нет
;* Выход:      RXBUF = принятый байт данных
;*****************************************************************************
RXI2C
         movlw .8       ; 8 бит данных
         movwf COUNT
         clrf EEBUF
RXlp
         call BITIN     ; новый бит в CARRY
         rlf EEBUF,F    ; ввод нового бита
         decfsz COUNT,F ; обработано 8 бит?
         goto RXlp
         return
 
;*****************************************************************************
;* BITIN
;* Прием одного бита
;*
;* Вход:    нет
;* Выход:   EEBUF, 0 принятый бит
;*****************************************************************************
BITIN
         bsf STATUS,RP0 ; выбор RAM bank 1
         bsf SDA        ; установка SDA для ввода
         bcf STATUS,RP0 ; обратно в RAM bank 0
         bsf SCL        ; SCL = 1
         nop
         nop
         nop
         nop            ; предоставляется минимальное время установки
         CLRC
         btfsc SDA      ; чтение SDA в CARRY
         bsf STATUS,C
         bcf SCL        ; возврат с SCL = 0
         return
 
;*****************************************************************************
;* Генерация бита START
;*
;* Вход:    нет
;* Выход:   инициализирован обмен по шине
;*****************************************************************************
BSTART
         bsf STATUS,RP0 ; выбор RAM bank 1
         bsf SDA        ; вход SDA (pull up -> 1)
         bcf STATUS,RP0 ; обратно в RAM bank 0
         bsf SCL        ; SCL = 1
         nop
         nop
         nop
         nop            ; 5 мкс перед спадом SDA
         bsf STATUS,RP0 ; выбор RAM bank 1
         bcf SDA        ; выход SDA
         bcf STATUS,RP0 ; обратно в RAM bank 0
         bcf SDA        ; SDA = 0
         nop
         nop
         nop
         nop            ; 4 мкс перед спадом SCL
         bcf SCL        ; начало последовательности тактов
         return
 
;*****************************************************************************
;* Генерация бита STOP
;*
;* Вход:    нет
;* Выход:   STOP condition на шине
;*****************************************************************************
BSTOP
         bsf STATUS,RP0 ; выбор RAM bank 1
         bcf SDA        ; выход SDA
         bcf STATUS,RP0 ; обратно в RAM bank 0
         bcf SDA        ; SDA = 0
         bsf SCL        ; SCL = 1
         nop
         nop
         nop
         nop            ; 4 мкс перед нарастанием SDA
         bsf STATUS,RP0 ; выбор RAM bank 1
         bsf SDA        ; вход SDA (pull-up -> 1) пока SCL = 1
         bcf STATUS,RP0 ; обратно в RAM bank 0
         movlw ERR_STOP ; получение кода ошибки
         btfss SDA      ; лог. 1?
         call ERR       ; ошибка, SDA заблокирован перед STOP
         bcf SCL        ; SCL = 0
         return
 
;*****************************************************************************
;* TWI/I2C - таблица ошибок состояния обмена CPU
;*
;* Вход:    W-reg    = код ошибки
;* Выход:   ERCODE   = код ошибки
;*          FLAG(ERROR) = 1
;*****************************************************************************
ERR
         bcf STATUS,RP0 ; обратно в RAM bank 0; запись последней ошибки
         movwf ERCODE   ; сохранение кода ошибки
         bsf FLAG_EE    ; установка флага ошибки
         return

[Листинг 2: I2CAUTO.ASM]

         LIST n=0, c=132
         RADIX HEX
         PROCESSOR PIC16C62A
;**********************************************************************
;* Файл: I2CAUTO.ASM
;**********************************************************************
;* Автор: Lucio Di Jasio
;* Компания: Microchip Technology
;* Ревизия: RevA0
;* Дата: 5-7-98
;* Ассемблировано с помощью MPASM v02.15
;**********************************************************************
;* Подключаемые файлы:
;* p16c62A.inc rev1.01
;*
;**********************************************************************
;* Программное определение размера памяти I2C EEPROM.
;*
;*      PIC16CXXX                /+5V
;*    +-----------+              |
;*    |        Vdd+--------------+--------+    24CXXX
;*    |           |             +++       |  +--------+
;*    |           |             | |       +--+Vdd     |
;*    |           |             | | 4k7      |        |
;*    |           |             +++          |        |
;*    |        RC4+--------------+-----------+SDA     |
;*    |        RC3+--------------------------+SCL     |
;*    |           |                          |        |
;*    |        Vss+--------------+-----------+Vss     |
;*    +-----------+              |           +--------+
;*                              GND
;*
;* Можно проверить на PICDEM2 demo board.
;**********************************************************************
   INCLUDE     "P16C62A.INC"
   __CONFIG    _XT_OSC & _CP_OFF & _WDT_ON
   __IDLOCS    H'62A0'
;**********************************************************************
;* Внешний кварц 4 МГц
;* нет защиты кода
;* нет сторожевого таймера
;* ID code "62A0"
;**********************************************************************
; Назначение выводов
#define  SDA   PORTC,4     ; i I2C SDA
#define  SCL   PORTC,3     ; o I2C SCL
MASKA    equ   0FF         ; все не используемые входы
MASKB    equ   00          ; все выходы для подключения LED
MASKC    equ b'11110111'   ; на этом порте сигналы SCL и SDA
; SCL настраивается на выход
;------------------------------------------------------------
; Назначение RAM
   CBLOCK 20
      TEMP
      SIZELO      ; размер памяти
      SIZEHI
      TYPE        ; тип памяти
   ENDC
;**********************************************************************
         org 00   ; вектор сброса
         goto Start
 
;**********************************************************************
         org 04   ; вектор прерывания
         retfie   ; возврат с повторным разрешением прерываний
 
;**********************************************************************
   INCLUDE "i2c.inc"
;**********************************************************************
;* MemDetect: автоматическое определение размера памяти
;*
;* Вход:    нет
;* Выход:   SIZEHI/LO   детектированный размер памяти
;*          TYPE        тип памяти (см. таблицу ниже)
;*          FLAG_EE     флаг ошибки шины
;*          ERCODE      код ошибки шины
;*
;* Standard I2C                  Smart Serial
;* TYPE  SIZE  MODEL          TYPE  SIZE  MODEL
;* 01    128   24C01/21/41    32    4096  24C32
;* 02    256   24C02/62       64    8192  24C65/64
;* 04    512   24C04          128   16384 24C128
;* 08    1024  24C08          0     32768 24C256
;* 16    2048  24C16/164
;*
;**********************************************************************
MemDetect
         clrf INDHI     ; адрес 0000h
         clrf INDLO
         bsf SMART      ; write(smart, 0000, 1)
         movlw 1
         movwf DATO
         call WRbyte
         bcf SMART
         call RDbyte    ; read(standard, 0000)
         movf DATO,W
         btfsc STATUS,Z
         goto StandardD
 
SmartD
         bsf SMART      ; это Smart Serial
         movlw HIGH(.4096)
         movwf SIZEHI   ; размер = 4096 байт
         clrf SIZELO
         movlw .32
         movwf TYPE     ; начинаем с TYPE = 24C32
         goto TestD
 
StandardD
         bcf SMART      ; это Standard Serial
         movlw .128
         movwf SIZELO   ; размер = 128 byte
         clrf SIZEHI
         movlw 01
         movwf TYPE     ; начинаем с TYPE = 24C01
TestD
         call RDbyte    ; TEMP=read(0)
         movf DATO,W
         movwf TEMP
LoopDet  movf SIZELO,W  ; DATO=read(SMART, size)
         movwf INDLO
         movf SIZEHI,W
         movwf INDHI
         call RDbyte
         movf DATO,W
         xorwf TEMP,W   ; сравнение TEMP с DATO
         btfss STATUS,Z
         goto LoopDN
         incf TEMP,W    ; если равно, то TEMP=TEMP+1
         movwf TEMP
         movwf DATO
         clrf INDHI
         clrf INDLO
         call WRbyte    ; write(SMART, 0000, TEMP)
         movf SIZELO,W  ; if (read(SMART, size) == TEMP)
         movwf INDLO
         movf SIZEHI,W
         movwf INDHI
         call RDbyte
         movf DATO,w    ; если все еще одинаковое значение, то это значит,
         xorwf TEMP,W   ; что мы достигли реального размера памяти
         btfsc STATUS,Z
         goto DetEx
 
LoopDN
         bcf STATUS,C   ; удвоение размера памяти
         rlf SIZELO,F
         rlf SIZEHI,F
         bcf STATUS,C
         rlf TYPE,F     ; удвоение кода TYPE
         btfss TYPE,4
         goto LoopDet
 
DetEx
         nop
         return
 
;**********************************************************************
; Инициализация портов и регистра опций
Start
         bsf STATUS,RP0    ; выбор RAM bank 1
         movlw MASKA       ; установка регистров tris
         movwf PORTA       ; PORTA
         movlw MASKB       ;
         movwf PORTB       ; PORTB
         movlw MASKC       ;
         movwf PORTC       ; PORTC
         movlw b'00000111' ; разрешение pullup, прескалер TMR0 1:256
         movwf OPTION_REG
         bcf STATUS,RP0
         clrf FLAGS        ; сброс всех флагов
 
;**********************************************************************
Main
         call MemDetect    ; определение размера памяти
         movf TYPE,W       ; если используется плата PICDEM2, то
         movwf PORTB       ; TYPE отправляется на светодиоды LED
MainLoop
         goto MainLoop     ; зацикливание до сброса
   END

[Ссылки]

1. AN690 I2C Memory Autodetect site:microchip.com (00690a.pdf).
2. Best way to detect EEPROM size site:avrfreaks.net.
3. AN515 Communicating with I2C™ Bus Using the PIC16C5X, Bruce Negley.
4. AN535 Logic Powered Serial EEPROMs, R. J. Fisher and Bruce Negley.
5. AN558 Using the 24xx65 and the 24xx32 with Stand-alone PIC16C54 Code, Dick Fisher and Bruce Negley.
6. AN567 Interfacing the 24LCxxB Serial EEPROMs to the PIC16C54, Bruce Negley.
7. AN608 Converting to 24LCXXB and 93LCxx Serial EEPROMs, Nathan John.
8. AN536 Basic Serial EEPROM Operation, Steve Drehobl.
9. AN554 Software Implementation of I2C™ Bus Master, Amar Palacherla.
10. AN559 Optimizing Serial Bus Operations with Proper Write Cycle Times, Lenny French.
11. AN537 Serial EEPROM Endurance, Steve Drehobl.
12. AN602 How to get 10 Million Cycles Out of Your Microchip Serial EEPROM, David Wilkie.