 // Файл с основными определениями для AT45DB161E.
 // v 1.11 от 20/07/15
 // Автор: Сычев А.

 // используйте следующие макросы перед подключением этого заголовочного файла
 // AT45DB161E_APILEVEL - для доступа к структурам и типам низокуровневых функций
 // AT45DB161E_LOWLEVEL - для доступа ко всем низкоуровневым определениям
 //
 // например: # файл c API для работы с флешкой использует
 //             только интерфейсы, ему достаточно только AT45DB161E_APILEVEL
 //           # файл, который реализует низкоуровневые команды требует AT45DB161E_LOWLEVEL
 //           # пользовательский файл высокоуровневой программы вообще не требует этих макросов

#ifndef AT45DB161E_H
#define AT45DB161E_H

     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ ВВЕДЕНИЕ №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№


     // Чип состоит из 17 секторов, в т.ч. 2 уникальных и 15 обычных. Первые 2 считаются за 1.
     // Уникальные сектора - это разбитый на 2 части обычные, он меньше обычного по размеру.
     // В даташите эти секторы называются sector 0a и  sector 0b. Остальные
     // секторы нумеруются как обычно, 1...15.
     //
     // Сектор содержит от 1 до 32 блоков, обычный всегда содержит 32 блоков
     // Блок содержит всегда 8 страниц по 512+16 байт.
     // Первые 2 сектора - подсекторы 0го, 0a и 0b - уникальные. Первый (сектор 0a) содержит один блок (8страниц)
     // Второй уникальный (сектор 0b) - 31 блок. Остальные сектора (1,3,4...63) - содержат
     // по 32 блока

     // Чип позволяет хранить дополнительные 16 байт на каждые 512 байт в каждой странице
     // Это используется, например, для хранения контрольных сумм и кодов исправления ошибок.
     // Эти данные доступны при простом чтении страницы или последовательном чтении.
     // Однако можно запретить доступ к этим данным: программная эмуляция и аппаратная эмуляция
     // Программная эмуляция - эмуляция программными средствами API драйвера памяти. Она заключается
     // в том, что при чтении страницы читаются только первые 512 байт. Внимание! В этом режиме
     // недоступна команда последовательного чтения! Аппаратная эмуляция - использование
     // опции power of two чипа памяти, опция включается один раз, и более не выключается.
     // В этом режиме команда последовательного чтения работает.

     // Для того, чтобы включить программную эмуляцию 512 байтной страницы
     // объявите макрос AT45DB161E_EMU512=1
     // Для того, чтобы использовать опцию Power of two и навсегда установить
     // размер страницы 512 байт, объявите макрос AT45DB161E_PRM512
     // Используйте только один из макросов!

     // Чип позволяет прогаммно защищать секторы от стирания/записи. Для этого используются
     // команды снятия/установки защиты на выбранные секторы. При этом выбор секторов для защиты
     // осуществляется через специальный регистр защиты, содержимое которого определяет, какие
     // секторы будут защищены. Сам регистр защиты можно защитить только аппарано (пин WP).
     // Т.О. защита осуществляется в 2 этапа: изменение регистра защиты (стирание+запись) и
     // включение защиты. Причем не обязательно в этом порядке: можно не снимая защиты модифицировать
     // содержимое регистра не снимая защиты. Именно так рекомендуют действовать Atmel.
     // При стирании регистра защиты все секторы становятся защищены. Количество операций
     // записи/стирания регистра ограничено числом
     #define     __FLASH_PROTECTREGISTER_WRITECYCLES   10000

/* <CONFIG> */

     //#define AT45DB161E_EMU512     // включение/выключение сервисных байтов
     //#define AT45DB161E_PRM512     // запрещение сервисных байтов
     #include "drivers\flash\at45\config\AT45DB161E_CONF.h"

     #ifndef AT45DBXXX_API_TIMEOUT
     #define AT45DBXXX_API_TIMEOUT _TIME_FLASHAPI_TIMEOUT
     #endif
/* </CONFIG> */

     // Библиотека позволяет исключить циклы ожидания после
     // длительных команд, переложив ожидание ПОСЛЕ команды
     // в ожидание ПЕРЕД командой - активное ожидание освобождения
     // устройства через сканирования флага BUSY в статусном регистре.
     // Библиотека в любом случае использует чтение флага перед
     // каждой низкоуровневой командой, но делает это обычно 1 раз,
     // возвращая ошибку после неудачи. Используйте макрос AT45DB161E_BKGOPERATIONS=1,
     // для того, чтобы использовать постоянное сканирование флага
     // перед командой вместо ожидания в конце команды. Используя данный режим,
     // будьте внимательны при сохранении данных перед выключением питания.

     // Библиотека позволяет использовать "умные" задержки после длительных
     // операций. Это означает, что ожидание после команды представляет собой
     // периодическое сканирование флага BUSY. Заданная в спецификации задержка
     // разбивается на квантованные промежутки времени, через которые происходит
     // опрос занятости устройства. Так предположительно длительная задержка
     // может быть сокращена при досрочном освобождении устройства. По умолчанию
     // режим "умных" задержек включен. Для выключения объявите макрос AT45DB161E_DONTUSESMARTDELAY=1
     // Режим "умных" задержек используется для обеспечения МИЛЛИСЕКУНДНЫХ задержек более AT45DBXXX_SMART_WAIT_THRESHOLD миллисекунд

/* <CONFIG> */
     //#define AT45DB161E_DONTUSESMARTDELAY 0 // отключение "умной" задержки
     //#define AT45DB161E_BKGOPERATIONS     0 // отключение задержек операций | ВНИМАНИЕ! Только для ОПЫТНЫХ пользователей (-: !!!

/* </CONFIG> */
     //--------------------------------------------------------------
     // Иерархия распределения секторов, блоков и страниц.
     // Номера блоков - отнисительно сектора
     // Номера страниц - отнисительно блока
     //--------------------------------------------------------------

     //  AT45DB161E
     //  _________
     //      |
     //      |-[-] Сектор 0a / Уникальный сектор, содержит только 1 блок
     //      |  |
     //      |  |-[-] Блок 0
     //      |     |___ Страница 0, блок 0 сектора 0
     //      |     .
     //      |     .
     //      |     .
     //      |     |___ Страница 7, блок 0 сектора 0
     //      |
     //      |
     //      |-[-] Сектор 0b / Уникальный сектор, содержит только 31 блок
     //      |  |
     //      |  |-[-] Блок 0
     //      |  |  |___ Страница 0, блок 0 сектора 1
     //      |  |  .
     //      |  |  |___ Страница 7, блок 0 сектора 1
     //      |  |
     //      |  |-[-] Блок 1
     //      |  |  |___ Страница 0, блок 1 сектора 1
     //      |  |  |___ Страница 1, блок 1 сектора 1
     //      |  |  .
     //      |  |  .
     //      |  |  .
     //      |  |  |___ Страница 7, блок 1 сектора 1
     //      |  .
     //      |  .
     //      |  .
     //      |  |-[-] Блок 30
     //      |     |
     //      |     |___ Страница 0, блок 30 сектора 1
     //      |     .
     //      |     .
     //      |     .
     //      |     |___ Страница 7, блок 30 сектора 1
     //      |
     //      |
     //      |-[-] Сектор 1 / Обычный сектор, содержит 32 блока
     //      |  |
     //      |  |-[-] Блок 0
     //      |  |  |
     //      |  |  |___ Страница 0, блок 0 сектора 2
     //      |  |  .
     //      |  |  .
     //      |  |  .
     //      |  |  |___ Страница 7, блок 0 сектора 2
     //      |  |
     //      |  |-[-] Блок 1
     //      |  |  |
     //      |  |  |___ Страница 0, блок 1 сектора 2
     //      |  |  .
     //      |  |  .
     //      |  |  .
     //      |  |  |___ Страница 7, блок 1 сектора 2
     //      |  |
     //      |  |-[+] Блок 2
     //      |  .
     //      |  .
     //      |  .
     //      |  |-[+] Блок 30
     //      |  |-[+] Блок 31
     //      |
     //      |-[+] Сектор 2 / Обычный сектор, содержит 32 блока
     //      |-[+] Сектор 3 / Обычный сектор, содержит 32 блока
     //      .
     //      .
     //      .
     //      |-[+] Сектор 15 / Обычный сектор, содержит 32 блока
     //
     //----------------------------------------------------------------------------------------------------------

     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ Внутренние определения №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№

     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##
     // ##                                                          ##
     // ##                 Распределение памяти                     ##
     // ##                                                          ##
     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##

     // размер страницы
         #define __FULL_PAGE_SIZE   528    // размер страницы дополнен 16-ю байтами для служебной информации
         #define __DATA_PAGE_SIZE   512
         // страницы не совсем стандартные - каждая страница имеет 512 байт данных и 16 байт служебной информации
         // Все эти байты читаются и пишутся обычным образом. Но для замены стандартных решений (вроде AT25XXX), удобнее
         // эмулировать наличие 512 байт в странице, отбросив 16 служебных.
         #if defined(AT45DB161E_EMU512) || defined(AT45DB161E_PRM512)

           #ifdef AT45DB161E_PRM512
               #define __PAGE_SIZE        __DATA_PAGE_SIZE // размер страницы: для API
           #else
               #define __PAGE_SIZE        __FULL_PAGE_SIZE // размер страницы: для API
           #endif

           #define __PAGE_SIZE_USER   __DATA_PAGE_SIZE // размер страницы: для пользователя

         #else

           #define __PAGE_SIZE        __FULL_PAGE_SIZE // размер страницы: для API
           #define __PAGE_SIZE_USER   __FULL_PAGE_SIZE // размер страницы: для пользователя

         #endif

     // размер блока
         #define __PAGES_PER_BLOCK  8
         #define __BLOCK_SIZE       ( __PAGES_PER_BLOCK * __PAGE_SIZE )
         #define __BLOCK_SIZE_USER  ( __PAGES_PER_BLOCK * __PAGE_SIZE_USER )

     // Количество секторов, блоков
     // Сектора разного размера: всего их 17 (1+1+15)
     // Первый и второй - имеют хитрый размер, остальные - одинаковые, по 32 блока, т.е. по 256 страниц
         #define __SECTORS_FULL     17    // полное количество секторов (нулевой состоит из двух)
         #define __SECTORS_TYPICAL  16    // типовое количество секторов
         #define __SECTORS          __SECTORS_TYPICAL
         #define __BLOCKS            512  // полное количество блоков
         #define __BLOCKS_PER_SECTOR 32   // количество блоков в секторе
         #define __FULL_PAGES        (__BLOCKS * __PAGES_PER_BLOCK)
         #define __PAGES_PER_SECTOR  (__BLOCKS_PER_SECTOR * __PAGES_PER_BLOCK )

     // размеры секторов
         #if defined(AT45DB161E_PRM512) || defined(AT45DB161E_EMU512)
           #define __SECTOR_STD_SIZE  0x20000       // 128K
           #define __SECTOR0_A_SIZE   0x1000        // 4K
           #define __SECTOR0_B_SIZE   0x1F000       // 124K
         #else
           #define __SECTOR_STD_SIZE  0x21000       // 128K + 4K
           #define __SECTOR0_A_SIZE   0x1080        // 4K  + 128
           #define __SECTOR0_B_SIZE   0x1FF80       // 124K + 3968
         #endif

         #define __SECTOR1_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR2_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR3_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR4_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR5_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR6_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR7_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR8_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR9_SIZE     __SECTOR_STD_SIZE
         #define __SECTOR10_SIZE    __SECTOR_STD_SIZE
         #define __SECTOR11_SIZE    __SECTOR_STD_SIZE
         #define __SECTOR12_SIZE    __SECTOR_STD_SIZE
         #define __SECTOR13_SIZE    __SECTOR_STD_SIZE
         #define __SECTOR14_SIZE    __SECTOR_STD_SIZE
         #define __SECTOR15_SIZE    __SECTOR_STD_SIZE

         #define __FULL_CHIP_SIZE   (__BLOCKS * __PAGES_PER_BLOCK * __FULL_PAGE_SIZE)
         #define __FULL_DATA_SIZE   (__BLOCKS * __PAGES_PER_BLOCK * __DATA_PAGE_SIZE)

         #include "drivers\flash\base\flash_api_types.h"

#ifdef AT45DB161E_LOWLEVEL
     //---------------------------------------------------------------
     // Чип имеет 2 встроенных SRAM буфера по 528 байт для проведения
     // операций чтения/записи и сравнения. Чип позволяет читать
     // данные последовательно, страницу за страницей (послед. чтение).
     // Также возможна запись содержимого буфера в память со стиранием,
     // при этом стирание происходит автоматически.

     //---------------------------------------------------------------
     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##
     // ##                                                          ##
     // ##                   команды обмена                         ##
     // ##                                                          ##
     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##

     // чтение
       #define _RCMD_ARRYREAD     0xE8            // последовательное чтение
       #define _LCMD_ARRYREAD     0x03            // последовательное чтение (до 33MHz)
       #define _HCMD_ARRYREAD     0x0B            // последовательное чтение (до 66MHz)
       #define _RCMD_PAGEREAD     0xD2            // чтение одной страницы
       #define _RCMD_BUF1READ     0xD4            // чтение содержимого буфера 1
       #define _RCMD_BUF2READ     0xD6            // чтение содержимого буфера 2
       #define _LCMD_BUF1READ     0xD1            // чтение содержимого буфера 1 (до 33MHz)
       #define _LCMD_BUF2READ     0xD3            // чтение содержимого буфера 2 (до 33MHz)
     // запись
       #define _WCMD_BUF1WRIT     0x84            // Запись в буфер 1
       #define _WCMD_BUF2WRIT     0x87            // Запись в буфер 2
       #define _WCMD_BUF1PROG     0x83            // Запись содержимого буфера 1 в страницу
       #define _WCMD_BUF2PROG     0x86            // Запись содержимого буфера 2 в страницу
       #define _WCMD_BUF1PRGx     0x88            // Запись содержимого буфера 1 в страницу БЕЗ стирания
       #define _WCMD_BUF2PRGx     0x89            // Запись содержимого буфера 2 в страницу БЕЗ стирания
       // можно писать в страницу без дополнительных буферных команд, пропуская данные через буфер 1 или 2
       #define _WCMD_PGB1WRIT     0x82            // Запись страницы через буфер 1 (Запись в буфер+Стирание страницы+Запись буфера)
       #define _WCMD_PGB2WRIT     0x85            // Запись страницы через буфер 2 (Запись в буфер+Стирание страницы+Запись буфера)
     // Стирание: Чип позволяет стирать память по-странично, и по-блочно
       #define _ECMD_PAGERASE     0x81            // Стирание страницы
       #define _ECMD_BLKERASE     0x50            // Стирание блока из 8 страниц (удобно использовать вместе с __CMD_PRGxBUF1 и __CMD_PRGxBUF2 )
     // по-секторнор
      #define _ECMD_SCTERASE     0x7C             // Стирание сектора 0a,0b,1-63
     // или целиком (последовательность 4 команд-байт)
       #define _ECMD_CHPERAS0     0xC7            // Стрирание чипа, байт №0
       #define _ECMD_CHPERAS1     0x94            // Стрирание чипа, байт №1
       #define _ECMD_CHPERAS2     0x80            // Стрирание чипа, байт №2
       #define _ECMD_CHPERAS3     0x9A            // Стрирание чипа, байт №3
       #define _ECMD_CHPERASE     0xC794809A      // Стрирание чипа (обратный порядок байт)
       #define _ECMD_CHPERASE_DIRECT 0x9A8094C7   // Стрирание чипа
     // дополнительные команды
     // Можно сравнивать фрагменты в буферах со страницами в памяти
       #define _ACMD_BUF1LOAD     0x53            // Загрузка страницы в буфер 1 (предварительное чтение, используется, например, для сравнения)
       #define _ACMD_BUF2LOAD     0x55            // Загрузка страницы в буфер 2 (предварительное чтение, используется, например, для сравнения __CMD_BUF1CMPR/__CMD_BUF2CMPR)
       #define _ACMD_BUF1CMPR     0x60            // Сравнение содержимого буфера 1 со страницей
       #define _ACMD_BUF2CMPR     0x61            // Сравнение содержимого буфера 2 со страницей
     // Производитель требует хотябы однажды за каждые 20000 операций записи/стирания страницы
     // в секторе проводить перезапись всех остальных страниц в секторе. Для этого введена специальная
     // команда обновления страницы __CMD_PAGEREF1 (__CMD_PAGEREF2), использующая буфер 1 или 2 для
     // чтения страницы и записи ее на то же место (обновление страницы)
     /* <quote>To preserve data integrity, each page of an Atmel DataFlash sector must be updated/rewritten at least once within
     every 20,000 cumulative page erase and program operations. </quote> */
       #define _ACMD_PAGEREF1     0x58            // Обновление страницы через буфер 1
       #define _ACMD_PAGEREF2     0x59            // Обновление страницы через буфер 2
       // чип поддерживает энергосберегающий режим
       #define _ACMD_EPWRDOWN     0xB9            // переход в спящий режим
       #define _ACMD_LPWRDOWN     0xAB            // выход их спящего режима
       #define _ACMD_STATREAD     0xD7            // чтение статусного регистра
       #define _ACMD_MFIDREAD     0x9F            // чтение информации о производителе и ID микросхемы
       // команды совместимости со старыми чипами
       #define _OCMD_BUF1READ     0x54            // чтение содержимого буфера 1 (совместимость)
       #define _OCMD_BUF2READ     0x56            // чтение содержимого буфера 2 (совместимость)
       #define _OCMD_PAGEREAD     0x52            // чтение одной страницы (совместимость)
       #define _OCMD_ARRYREAD     0x68            // последовательное чтение (совместимость)
       #define _OCMD_STATREAD     0x57            // чтение статусного регистра (совместимость)
       // команды защиты
       #define _SCMD_4SCTPREN     0x3D2A7FA9      // включить защиту секторов (обратный порядок байт)
       #define _SCMD_4SCTPRDS     0x3D2A7F9A      // выкючить защиту секторов (обратный порядок байт)
       #define _SCMD_4PRREGER     0x3D2A7FCF      // стереть регистр защиты стирания (protect) (обратный порядок байт)
       #define _SCMD_4PRREGWR     0x3D2A7FFC      // Записать регистр защиты стирания (protect) (обратный порядок байт)
       #define _SCMD_PRTREGRD     0x32            // прочитать регистр защиты стирания (protect)
       #define _SCMD_4SCTLKDN     0x3D2A7F30      // постоянная блокировка сектора (навсегда) (обратный порядок байт)
       #define _SCMD_LKDNRGRD     0x35            // прочитать регистр постоянной блокировки
       #define _SCMD_4SECRGWR     0x9B000000      // запись регистра безопасности (security) (обратный порядок байт)
       #define _SCMD_4SECRGRD     0x77000000      // чтение регистра безопасности (security) (обратный порядок байт)
       #define _PCMD_PGSZCNFG     0x3D2A80A6      // перепрограммирование размера страницы на 512 байт (НАВЕСГДА)  (обратный порядок байт)

       #define _SCMD_4SCTPREN_DIRECT     0xA97F2A3D      // включить защиту секторов
       #define _SCMD_4SCTPRDS_DIRECT     0x9A7F2A3D      // выкючить защиту секторов
       #define _SCMD_4PRREGER_DIRECT     0xCF7F2A3D      // стереть регистр защиты стирания (protect)
       #define _SCMD_4PRREGWR_DIRECT     0xFC7F2A3D      // Записать регистр защиты стирания (protect)
       #define _SCMD_4SCTLKDN_DIRECT     0x307F2A3D      // постоянная блокировка сектора (навсегда)
       #define _SCMD_4SECRGWR_DIRECT     0x0000009B      // запись регистра безопасности (security)
       #define _SCMD_4SECRGRD_DIRECT     0x00000077      // чтение регистра безопасности (security)
       #define _PCMD_PGSZCNFG_DIRECT     0xA6802A3D      // перепрограммирование размера страницы на 512 байт (НАВЕСГДА)



#endif
#if defined(AT45DB161E_APILEVEL) || defined(AT45DB161E_LOWLEVEL)

     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##
     // ##                                                          ##
     // ##                   максимальные времена                   ##
     // ##                                                          ##
     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##
     //
     // из колонки MAX таблицы временных характеристик чипа
       #define _TIME_CSSET_us     1               // время на установление CS в 1
       #define _TIME_CSCLR_us     1               // время на установление CS в 0
       #define _TIME_CSHLD_us     1               // минимальное время CS в неактивном состоянии м/у командами
       #define _TIME_EDPDM_us     3               // вход в спящий режим
       #define _TIME_RDPDM_us     35              // выход из спящего режима
       #define _TIME_BLDCM_us     300             // загрузка/сравнение буфера

       #define _TIME_RSTRC_us     1               // время восстановления после сброса
       #define _TIME_RSTWD_us     10              // время удержания сигнала сброса
       #define _TIME_STRUP_us     100             // время готовности после подачи питания (чип все еще не готов записывать данные)

       #define _TIME_PGPRG_ms     15/*6*/         // программирование страницы
       #define _TIME_START_ms     20              // ожидание запуска чипа до полной готовности
       #define _TIME_COOLDOWN_ms  20              // ожидание "остывания" чипа после выключения питания
       #define _TIME_PGERS_ms     35              // стирание страницы
       #define _TIME_PGEPR_ms     40              // стирание страницы + программирование страницы
       #define _TIME_BKERS_ms     100             // стирание блока
       #define _TIME_SCERS_ms     5000            // стирание сектора

       #define _TIME_FLASHAPI_TIMEOUT  10         // стандартный таймаут ожидания API-функций
#endif

#ifdef AT45DB161E_LOWLEVEL
     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##
     // ##                                                          ##
     // ##                     ДРУГИЕ ОПРЕДЕЛЕНИЯ                   ##
     // ##                                                          ##
     // ##__##__##__##__##__##__##__##__##__##__##__##__##__##__##__##

/* <CONFIG> */

     // положение всех используемых гломальных переменных в памяти RAM (секция)
     //#define FLASH_RAM_PLACE      ".at45"      // укажите имя секции в кавычках для размещения всех связанных с AT45DB161E данных в ней

     // ожидание освобождения устройства
     //#define AT45DBXXX_SMART_WAIT_THRESHOLD  10   // порог в мс, выше которого функция __flash_smart_waitms начнет опрашивать чип на предмет его занятости.

      #include "drivers\flash\at45\config\AT45DB161E_CONF.h"

/* </CONFIG> */
     // чтение идентификатора
       #define __FLASH_MANIDEX_OPCODE            0x7F       // Contunuation Code при чтении Manufacturer ID
       #define __FLASH_ATMEL_ID                0x001F    // индентификатор фирмы Atmel в поле Manufacturer ID
       #define __FLASH_INVALID_ID              0x00FF    // индентификатор фирмы Atmel в поле Manufacturer ID

       #define __FLASH_DENSITY_16MB              0x6     // Atmel' Density for 16Mbit: 00110
       #define __FLASH_FAMILY_DATAFLASH          0x1     // Atmel' Family for DataFlash: 001
       #define __FLASH_STATUS_DENSITY_SIGN       0xB     // комбинационный код Density в регистре статуса
#endif

#if defined(AT45DB161E_APILEVEL) || defined(AT45DB161E_LOWLEVEL)
     // регистр защиты - байты защиты
       #define __FLASH_PROTECTION_REG_ENABLE     0xFF    // байт регистра защиты - сектор защищен
       #define __FLASH_PROTECTION_REG_DISABLE    0x00    // байт регистра защиты - сектор НЕ защищен
       #define __FLASH_PROTECTION_REG_S0_ENABLE  0x3     // поле 0го байта регистра защиты - сектор 0 защищен
       #define __FLASH_PROTECTION_REG_S0_DISABLE 0x0     // поле 0го байта регистра защиты - сектор 0 НЕ защищен
#endif

#ifdef AT45DB161E_LOWLEVEL

     // оперативная память
       #define __FLASH_LL_COMMAND_MAXSIZE  8    // максимальное количество байт, выделяемое для буфера команд
                                                // максимальное количество байт, выделяемое для буфера команд + буфера страницы
       //#define __FLASH_LL_SVCMEM_SIZE      ( __FULL_PAGE_SIZE + __FLASH_LL_COMMAND_MAXSIZE + __SECTORS_TYPICAL )
         #define __FLASH_LL_SVCMEM_SIZE      (                    __FLASH_LL_COMMAND_MAXSIZE + __SECTORS_TYPICAL )
#endif

#if defined(AT45DB161E_APILEVEL) || defined(AT45DB161E_LOWLEVEL)
     // регистр безопасности
       #define __FLASH_USER_SECURITY_BYTES       64      // количество байт, доступных для программирования в регистре безопасности
       #define __FLASH_FACT_SECURITY_BYTES       64      // количество байт, запрограммированых в регистре безопасности производиелем
#endif
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ структуры и типы №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     //
#if defined(AT45DB161E_LOWLEVEL) || defined(AT45DB161E_APILEVEL)
     //-------------------------------------------
     #pragma pack( push, 1 )
     // РЕГИСТР СТАТУСА
     struct __flash_status_register_st
     {
          __FLASH_BYTE    bPageSize :  1;    // размер страницы 512(1)/528(0)
          __FLASH_BYTE    bProtect  :  1;    // защита секторов установлена(1)/снята(0)
          __FLASH_BYTE    cDensity  :  4;    // информация о размере памяти (устарело, см. даташит)
          __FLASH_BYTE    bMismatch :  1;    // бит "несовпадение" буфера и страницы (команда сравнения)
          __FLASH_BYTE    bReady    :  1;    // бит занятости BUSY. занят(0)/свободен(1)
     };
     #pragma pack( pop )
     typedef struct __flash_status_register_st __flash_status_t;
     //-------------------------------------------
     #pragma pack( push, 1 )
     // ИНДЕТИФИКАТОР ПРОИЗВОДИТЕЛЯ
     struct __flash_deviceid_st
     {
          __FLASH_BYTE    Density : 5;       // вместимость чипа (16Mbit=01011)
          __FLASH_BYTE    Family  : 3;       // семейство памяти (DataFlash=001)
          __FLASH_BYTE    Revision: 5;       // аппаратная версия
          __FLASH_BYTE    CellType: 3;       // тип ячейки памяти (SLC(single-level-cell),MLC(multi-level-cell),TLC(tripple-level-cell)); MLC: 000=1bit/cell
     };
     typedef struct __flash_deviceid_st flash_deviceid_t;

     struct __flash_manufacturerid_st
     {
       union {
       struct {
          __FLASH_BYTE          LowId;       // стандартный байт ID (не расширенный)
          __FLASH_BYTE         HighId;       // расширенный байт ID (количество 0x7F Continuation Code) (JEDEC JEP-106)
       };
          __FLASH_WORD         FullId;       // полный ID
       };
          __FLASH_WORD          DevId;       // код устройства

          __FLASH_BYTE         ExtLen;       // длинна расширенной информации
          __FLASH_BYTE *       pExtBf;       // указатель на буфер приемник расширенной информации
     };

     struct __flash_manufacturerid_ex_st
     {
       union {
       struct {
          __FLASH_BYTE          LowId;       // стандартный байт ID (не расширенный)
          __FLASH_BYTE         HighId;       // расширенный байт ID (количество 0x7F Continuation Code) (JEDEC JEP-106)
       };
          __FLASH_WORD         FullId;       // полный ID
       };
          flash_deviceid_t      DevId;       // код устройства

          __FLASH_BYTE         ExtLen;       // длинна расширенной информации
          __FLASH_BYTE *       pExtBf;       // указатель на буфер приемник расширенной информации
     };

     struct __flash_manufacturerid_returnvalue_st
     {
       union {
       struct {
          __FLASH_BYTE          LowId;       // стандартный байт ID (не расширенный)
          __FLASH_BYTE         HighId;       // расширенный байт ID (количество 0x7F Continuation Code) (JEDEC JEP-106)
       };
          __FLASH_WORD         FullId;       // полный ID
       };

         flash_deviceid_t      DevId;       // код устройства
     };

     typedef struct __flash_manufacturerid_returnvalue_st __flash_rvid_t;
     typedef struct __flash_manufacturerid_st             __flash_id_t;
     typedef struct __flash_manufacturerid_ex_st          __flash_exid_t;

     #pragma pack( pop )
     //-------------------------------------------
     #pragma pack( push, 1 )
     // РЕГИСТРЫ ЗАЩИТЫ/БЛОКИРОВКИ СЕКТОРОВ
     struct __flash_protect_register_sector0_st
     {
            __FLASH_BYTE prot_0a : 2;        // секция защиты сектора 0A (0-7 pages)
            __FLASH_BYTE prot_0b : 2;        // секция защиты сектора 0B (8-127 pages)
            __FLASH_BYTE reserved: 4;        // не используется
     };
     typedef struct __flash_protect_register_sector0_st __flash_protreg_s0_t;
     union __flash_protect_register_st
     {
          __flash_protreg_s0_t  Sector0;     // байт защиты сектора 0 ( __FLASH_PROTECTION_REG_S0_ENABLE / __FLASH_PROTECTION_REG_S0_DISABLE )

                                             // байты защиты секторов 0-63 (__FLASH_PROTECTION_REG_ENABLE / __FLASH_PROTECTION_REG_DISABLE )
          __FLASH_BYTE          Sectors[ __SECTORS_TYPICAL ];
     };
     typedef union __flash_protect_register_st __flash_protectionregister_t;
     typedef union __flash_protect_register_st __flash_lockdownregister_t;
     #pragma pack( pop )
     //-------------------------------------------
     // РЕГИСТРЫ БЕЗОПАСНОСТИ
     #pragma pack( push, 1 )
     struct __flash_usersecurity_register_st
     {
           __FLASH_BYTE       UserId[ __FLASH_USER_SECURITY_BYTES ];
     };
     typedef struct __flash_usersecurity_register_st __flash_usersecurityregister_t;
     struct __flash_factorysecurity_register_st
     {
           __FLASH_BYTE       UserId[ __FLASH_FACT_SECURITY_BYTES ];
     };
     typedef struct __flash_factorysecurity_register_st __flash_factorysecurityregister_t;
     struct __flash_security_register_st
     {
            __flash_usersecurityregister_t     UserPart;      // доступные для однократного программирования байты в регистре безопасности
            __flash_factorysecurityregister_t  FactoryPart;   // запрограммированные производителем байты в регистре безопасности
     };
     typedef struct __flash_security_register_st     __flash_securityregister_t;
     #pragma pack( pop )

     //-------------------------------------------
     // РЕГИСТРЫ КОНФИГУРАЦИИ: бит
     enum __flash_enum_pagesize
     {
          __fps_528 = 0,  // размер страницы - 528 байт (по умолчанию)
          __fps_512 = 1,  // размер страницы - 512 байт (по умолчанию)
          __fps_default  = __fps_528,       // 528 bytes / размер по умолчанию (с завода)
          __fps_standart = __fps_512,       // 512 байт  / стандартный размер
     };
     typedef enum __flash_enum_pagesize __flash_pagesize_t;

     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ преобразования адресов №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     //
     #if defined(AT45DB161E_LOWLEVEL) || defined(AT45DB161E_APILEVEL)

       // На размер страницы влияет макрос AT45DB161E_PRM512
       // На размер страниые НЕ влияет макрос AT45DB161E_EMU512

     //#define __FLASH_ADDRESS2SECTOR(addr)       ((addr)/__SECTOR_STD_SIZE)   // __FLASH_ADDRESS2SECTOR - преобразует адрес в номер сектора с учетом используемого размера страницы

       #define __FLASH_ADDRESS2PAGE(addr)         ((addr)/__PAGE_SIZE_USER)    // __FLASH_ADDRESS2PAGE - преобразует адрес в номер страницы с учетом используемого размера страницы
       #define __FLASH_PAGE2BLOCK(page)           ((page)/__PAGES_PER_BLOCK)   // __FLASH_PAGE2BLOCK - преобразует номер страницы в номер блока
       #define __FLASH_ADDRESSOFFSETPAGE(addr)    ((addr)%__PAGE_SIZE_USER)    // __FLASH_ADDRESSOFFSETPAGE - получает смещение адреса относительно начала страницы
                                                                               // __FLASH_DATAREMAININGINPAGE - вычисляет, какое количество байт осталось до конца страницы
       #define __FLASH_DATAREMAININGINPAGE(addr)  ( __PAGE_SIZE_USER - __FLASH_ADDRESSOFFSETPAGE( address ) )

       #define __FLASH_BASE_DENSITY               0x40000  // 256Kbit
       #define __FLASH_DENSITY2CAPACITY(density)  (__FLASH_BASE_DENSITY << (density) )

       // __FLASH_PAGESINRANGE - вычисляет, какое количество страниц находится на промежутке длинной size начиная с адреса address
       #define __FLASH_PAGESINRANGE(address,size) \
                                              ((address+size)/__PAGE_SIZE_USER - \
                                              (address)/__PAGE_SIZE_USER + \
                                              (((address+size)%__PAGE_SIZE_USER)?1:0))  //

       // __FLASH_PAGE_ARRAGED_BY_BLOCK - проверяет, выровнена ли страница на размер блока
       #define __FLASH_PAGE_ARRAGED_BY_BLOCK(pg)   (!( pg % AT45FLASH_PAGES_PER_BLOCK ))
     #endif
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ экпортируемые макросы №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№
     //
     // для экспорта функций используйте заголовочный файл "AT45DB161E_LL_func.h"

     #define AT45FLASH_ATMEL_ID         __FLASH_ATMEL_ID          // Atmel' Manufacturer ID
     #define AT45FLASH_DENSITY_16MB     __FLASH_DENSITY_16MB      // Atmel' Density for 32Mbit
     #define AT45FLASH_FAMILY_DATAFLASH __FLASH_FAMILY_DATAFLASH  // Atmel' Family code
     #define AT45FLASH_CHIP_SIZE        __FULL_CHIP_SIZE          // полный объем чипа
     #define AT45FLASH_DATA_SIZE        __FULL_DATA_SIZE          // полный объем данных (с учетом или без учета сервисных байтов)
     #define AT45FLASH_SECTORS          __SECTORS                 // количество секторов
     #define AT45FLASH_PAGE_SIZE        __PAGE_SIZE_USER          // размер страницы (зависит от использования сервисных секторов)
     #define AT45FLASH_BLOCKS           __BLOCKS                  // количество блоков
     #define AT45FLASH_BLOCK_SIZE       __BLOCK_SIZE_USER         // размер блока    (зависит от использования сервисных секторов)
     #define AT45FLASH_PAGES            __FULL_PAGES              // количество страниц
     #define AT45FLASH_BLOCKS_PER_SECTOR __BLOCKS_PER_SECTOR      // количество блоков в секторе
     #define AT45FLASH_PAGES_PER_SECTOR __PAGES_PER_SECTOR        // количество страниц в стандартном секторе
     #define AT45FLASH_PAGES_PER_BLOCK  __PAGES_PER_BLOCK

     //-------------------------------------------
     // размеры секторов
     #define AT45FLASH_SECTOR0_SIZE    (__SECTOR0_A_SIZE + __SECTOR0_B_SIZE)
     #define AT45FLASH_SECTOR0A_SIZE   __SECTOR0_A_SIZE
     #define AT45FLASH_SECTOR0B_SIZE   __SECTOR0_B_SIZE
     #define AT45FLASH_SECTOR1_SIZE    __SECTOR1_SIZE
     #define AT45FLASH_SECTOR2_SIZE    __SECTOR2_SIZE
     #define AT45FLASH_SECTOR3_SIZE    __SECTOR3_SIZE
     #define AT45FLASH_SECTOR4_SIZE    __SECTOR4_SIZE
     #define AT45FLASH_SECTOR5_SIZE    __SECTOR5_SIZE
     #define AT45FLASH_SECTOR6_SIZE    __SECTOR6_SIZE
     #define AT45FLASH_SECTOR7_SIZE    __SECTOR7_SIZE
     #define AT45FLASH_SECTOR8_SIZE    __SECTOR8_SIZE
     #define AT45FLASH_SECTOR9_SIZE    __SECTOR9_SIZE
     #define AT45FLASH_SECTOR10_SIZE   __SECTOR10_SIZE
     #define AT45FLASH_SECTOR11_SIZE   __SECTOR11_SIZE
     #define AT45FLASH_SECTOR12_SIZE   __SECTOR12_SIZE
     #define AT45FLASH_SECTOR13_SIZE   __SECTOR13_SIZE
     #define AT45FLASH_SECTOR14_SIZE   __SECTOR14_SIZE
     #define AT45FLASH_SECTOR15_SIZE   __SECTOR15_SIZE

     // количество циклов перезаписи регистра защиты
     #define AT45FLASH_PROTREG_WRITECOUNT  __FLASH_PROTECTREGISTER_WRITECYCLES

     // зарезервированная область в начале адресного пространства
     #define AT45FLASH_MINIMUM_ADDRESS  (AT45FLASH_SECTOR0_SIZE)

     // максимально возможный адрес
     #define AT45FLASH_MAXIMUM_ADDRESS  (AT45FLASH_PAGES * __PAGE_SIZE_USER )
     //-------------------------------------------
     // блок проверки режима эмуляции
     #ifdef   AT45DB161E_EMU512
     #ifdef   AT45DB161E_PRM512
     #undef   AT45DB161E_PRM512
     #error   Внимание! Вы неправильно объявили режим эмуляции страницы 512 байт.
     #endif
     #endif

#if defined( AT45DB161E_APILEVEL )
     #ifdef   AT45DB161E_EMU512
     #warning Внимание! Выбран режим программной эмуляции страниц 512 байт
     #endif

     #ifdef   AT45DB161E_PRM512
     #warning Внимание! Выбран режим аппаратной эмуляции страниц 512 байт
     #warning Будьте внимательны! После первого запуска отключить данный режим будет невозможно!
     #endif
#endif

#endif
#endif

