// Файл с низкоуровневыми коммандами для AT45DB321D. // v 1.4 от 28/07/15 // Автор: Сычев А. // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№ НИЗКОУРОВНЕВЫЕ НЕБЕЗОПАСНЫЕ ФУНКЦИИ №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ #define AT45DB321D_LOWLEVEL #include "drivers\flash\common\AT45DBXXX_TYP.h" #include "drivers\flash\common\AT45DBXXX_HAL.h" // аппаратная абстрация от SSP #include "drivers\flash\lowlevel\AT45DB321D_LL.h" // определения для AT45DB321D #include "drivers\flash\lowlevel\AT45DB321D_LL_func.h" // прототипы LL-функций // ######################################################################################################## // Глобальные переменные #pragma pack( push, 1 ) #ifdef FLASH_RAM_PLACE _PLACEIN( FLASH_RAM_PLACE ) #endif static union /* __flash_global */ { __FLASH_BYTE alloc_place[ __FLASH_LL_SVCMEM_SIZE ]; struct /* __flash_var */ { // __FLASH_BYTE pagebuffer[ __FULL_PAGE_SIZE ]; // НЕ ТРЕБУЕТСЯ! буфер под чтение/запись страниц union { __FLASH_BYTE protectbuffer[ __SECTORS_TYPICAL ]; // буфер под чтение/запись байтов защиты секторов __flash_protectionregister_t protectionregister; }; __FLASH_BYTE cmdbuffer [ __FLASH_LL_COMMAND_MAXSIZE ]; // буфер для выполения команд }; }; #pragma pack( pop ) __flash_protectionregister_t * __flash_internal_getbuffer_protect() { return &protectionregister; } // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // служебные функции управления CS // установка сигнала ChipSelect в активное состояние static inline void chip_sel_active() { __FLASH_HAL_CS_LO(); __FLASH_WAITus(_TIME_CSCLR_us); } // установка сигнала ChipSelect в неактивное состояние static inline void chip_sel_inactive() { __FLASH_WAITus(_TIME_CSSET_us); __FLASH_HAL_CS_HI(); __FLASH_WAITus(_TIME_CSHLD_us); // минимальное время между командами } #ifndef __imp_ssp_io_rev // Функция обращения порядка байтов и передачи по SPI // // @count не может быть 0. Функция не проверяет параметр! static void __int_ssp_io_rev( __FLASH_BYTE * pBuffer, __FLASH_WORD count ) { // обмениваем половину из count байт, т.к. вторая будет обменяна автоматически // вычитаем count-- чтобы прерватить count в индекс конеца буфера __FLASH_DWORD c = (count--) >> 1; // начианем обмен for( int i = 0; i < c; ++i ) { // Обмениваем pBuffer[i] с pBuffer[count-i] pBuffer[i] ^= pBuffer[count-i]; pBuffer[count-i] ^= pBuffer[i]; pBuffer[i] ^= pBuffer[count-i]; } // используем штатую функцию передачи байт по SPI __FLASH_HAL_WR( pBuffer, ++count ); } #endif #if AT45DBXXX_NO_MS_DELAYS == 1 // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // __int_sys_delayms - служебная функция ожидания в мс, если аналог отсутствует у пользователя. // Опция AT45DBXXX_NO_MS_DELAYS позволяет заменить задержку в мс на задержку в мкс. static inline void __int_sys_delayms( __FLASH_WORD timeout ) { __imp_sys_delayus( timeout * 1000 ); } #endif // -------------------------------------------------------------------------------------------------------- // __flash_smart_waitms - комбинированая функция ожидания заданного количества миллисекунд с // проверкой состояния чипа на предмет того, занят он, или нет. Если не занят, // функция возвращает управление сразу же. Если занят все указанное время, // функция возвратит управление через указанный таймаут (не меньший, но, возможно, больший). // // * не изменяет содержимое внутренних SRAM буферов // * использует системные вызовы для определения количества прошедшего времени // * потоко-небезопасная функция // * производит опрос чипа командой "Запрос статусного регистра" (Status Register Read) // * функция использует вызов функций бесконечного чтения статуса // static void __flash_hal__part_statusread_stage1( __flash_status_t * pcReadRegister ); static void __flash_hal__part_statusread_stage2( __flash_status_t * pcReadRegister ); static void __flash_hal__part_statusread_stage3( __flash_status_t * pcReadRegister ); // // * функция возвращает 1, если достоверно известно, что флаг BUSY сброшен (устройство готово), иначе 0 (требуется повторная проверка) // int __flash_smart_waitms( __FLASH_WORD wTimems ) { __flash_status_t r_status; // статус-регистр __flash_hal__part_statusread_stage1( &r_status ); // начинаем считывать // -- -- -- -- -- -- для коротких задержек -- -- -- -- -- -- -- -- -- -- #ifdef FLASH_CHECKSTATUS_DENSITYCODE #if FLASH_CHECKSTATUS_DENSITYCODE == 1 if ( r_status.cDensity == __FLASH_STATUS_DENSITY_SIGN ) // Дополнительная проверка на код Density #endif #endif if ( r_status.bReady ) // сразу проверяем, если устройство свободно, возвращаем управление { __flash_hal__part_statusread_stage3( 0 ); // завершаем чтение регистра return 1; } if ( wTimems < __FLASH_SMART_WAIT_THRESHOLD ) // для малых времен ожидания накладно опрашивать чип постоянно { __FLASH_WAITms(wTimems); // выжидаем указанное время __flash_hal__part_statusread_stage3( &r_status ); // проверяем регистр #ifdef FLASH_CHECKSTATUS_DENSITYCODE #if FLASH_CHECKSTATUS_DENSITYCODE == 1 if ( r_status.cDensity == __FLASH_STATUS_DENSITY_SIGN ) // Дополнительная проверка на код Density #endif #endif if ( r_status.bReady ) // если свободно - вернем 1 return 1; return 0; // если занято - вернем 0 } // -- -- -- -- -- -- для длинных задержек -- -- -- -- -- -- -- -- -- -- __FLASH_DWORD dwStartCounter = __FLASH_SMART_GETTIMER(); // получаем отметку времени for(/*|*/ __FLASH_DWORD dwDeltaCounter = 0; // счетчик задержки /*|*/ dwDeltaCounter < wTimems; // проверяем, задержались ли мы на указанное время или еще нет /*|*/ dwDeltaCounter = ( __FLASH_SMART_GETTIMER() - dwStartCounter ) ) // обновляем счетчик задержки { __flash_hal__part_statusread_stage2( &r_status ); // читаем статус #ifdef FLASH_CHECKSTATUS_DENSITYCODE #if FLASH_CHECKSTATUS_DENSITYCODE == 1 if ( r_status.cDensity == __FLASH_STATUS_DENSITY_SIGN ) // Дополнительная проверка на код Density #endif #endif if ( r_status.bReady ) // проверяем, не освободился ли чип? { __flash_hal__part_statusread_stage3( 0 ); // да, освободился, завершаем чтение return 1; // возвращаем 1 (освободился) } __FLASH_WAITms(1); // выжидаем квант времени } __flash_hal__part_statusread_stage3( &r_status ); // время вышло, завершаем чтение if ( r_status.bReady ) // последний раз проверяем статус return 1; // свободен! return 0; // чип до сих пор занят } // ######################################################################################################## // -------------------------------------------------------------------------------------------------------- // __flash_hal__part_statusread - группа скрытых низкоуровневых функций, позволяющая осуществлять постоянное сканирование регистра // статуса. Чип предоставляет возможность считывать регистр статуса без отправки команды на чтение при повторном чтении, // до установки CS в неактивное положение. Т.О возможно передать команду один раз, затем читать статус бесконечно. // Функции должны вызываться в порядке нумерации, при этом стадия 2 может быть пропущена. Функии проверяют параметр // pcReadRegister на NULL, если он отличен от NULL, считывают в него содержмое регистра, иначе ничего не считывают. // Пример ожидания завершения операции стирания: // [code] // // __flash_status_t status; // статус-регистр // // __flash_hal_pageerase( 0 ); // стираем 0 страницу // __flash_hal__part_statusread_stage1( &status ); // иницируем чтение статуса // // while( !status.bReady ) // __flash_hal__part_statusread_stage2( &status ); // повторяем чтение статуса // // __flash_hal__part_statusread_stage3( 0 ); // завершаем чтение статуса // // [/code] // __flash_hal__part_statusread_stage1 - 1 стадия (начальная) команды бесконечного чтения статуса занятости // __flash_hal__part_statusread_stage2 - 2 стадия (промежуточная) команды бесконечного чтения статуса занятости // __flash_hal__part_statusread_stage3 - 3 стадия (заключительная) команды бесконечного чтения статуса занятости // // * потоко-небезопасная функция // * НЕ задерживает выполнение: требуется внешний цикл для организации сканирования static void __flash_hal__part_statusread_stage1( __flash_status_t * pcReadRegister ) { chip_sel_active(); ( (__flash_packet_statusread_t*) cmdbuffer )->opcode = _ACMD_STATREAD; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statusread_t) ); if( pcReadRegister ) // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status_t) ); } //----- ------- ------ ------ ------ ------- ------ static void __flash_hal__part_statusread_stage2( __flash_status_t * pcReadRegister ) { if( pcReadRegister ) // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status_t) ); } //----- ------- ------ ------ ------ ------- ------ static void __flash_hal__part_statusread_stage3( __flash_status_t * pcReadRegister ) { if( pcReadRegister ) // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__getpagesize - получение размера страницы 512/528 байт // __flash_pagesize_t __flash_hal__getpagesize( ) { __flash_status_t status; __flash_hal__statusread( &status ); if( status.bPageSize == __fps_512 ) return __fps_512; return __fps_528; } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__getreadyfast - проверка занятости без ожидания // // # Возвращаемое значение: FLERR_SUCCESS если свободен, иначе FLERR_TIMEOUT flash_err_t __flash_hal__getreadyfast( ) { __flash_status_t status; __flash_hal__statusread( &status ); if( status.bReady ) return FLERR_SUCCESS; return FLERR_TIMEOUT; } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__getcompareresult - проверка результата сравнения (бит COMP / bMismatch) // // # Возвращаемое значение: FLERR_SUCCESS если совпадает, иначе FLERR_VERIFY_ERROR flash_err_t __flash_hal__getcompareresult( ) { __flash_status_t status; __flash_hal__statusread( &status ); if( status.bMismatch ) return FLERR_VERIFY_ERROR; return FLERR_SUCCESS; } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__getprotectstate - получение состояния общего бита защиты // // # Возвращаемое значение - FLERR_PROTECT_ENABLED, если бит защиты установлен, иначе FLERR_PROTECT_DISABLED flash_err_t __flash_hal__getprotectstate( ) { __flash_status_t status; __flash_hal__statusread( &status ); if( status.bProtect ) return FLERR_PROTECT_ENABLED; return FLERR_PROTECT_DISABLED; } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__detect - Низкоуровневое определение наличия чипа (доступности) // Используется во время первичной инициализации в flash_initialize(). flash_err_t __flash_hal__detect() { // сначала пытаемся прочитать идентификатор: // чтение регистра информации __FLASH_DWORD flashID = __flash_hal__manufactureridread( 0 ); // определяем наличие флешки по идентификатору if( ((__flash_rvid_t*) &flashID)->FullId == __FLASH_INVALID_ID ) { // похоже, что чипа нет, обнаружить не удалось return FLERR_LL_INITFAIL_NOTFOUND; } __flash_securityregister_t securityRegister; if( !__flash_hal__securityregister_validate( &securityRegister ) ) { // похоже, что чипа нет, обнаружить не удалось return FLERR_LL_INITFAIL_NOTFOUND; } // еще не все, нужно убедиться, что устройство отвечает: // читаем статус if( ! __flash_smart_waitms( _TIME_FLASHAPI_TIMEOUT ) ) { // либо статус не читается, либо устройство занято. // т.к. функция предназначена для использования во время инициализации, // предполагается, что чип должен быть свободен. // Поэтому возвращаем ошибку return FLERR_UNEXPECTED_BUSY; } return FLERR_SUCCESS; } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__finalize_prepare - Низкоуровневая функция для подготовки флешпамяти к деинициализации драйвера // Выполняет действия, направленные на завершение работы с флешпамятью и подготовки ее к выключению // Вызывается в момент окончательной остановки работы с флешпамятью flash_err_t __flash_hal__finalize_prepare() { // Сначала требуется проверить режим защиты записи: // если разрешено управление аппаратным сигналом защиты записи #if AT45DB321D_HW_WR_PROTECT // если аппаратная защита записи отключена в настройках #if AT45DB321D_HW_WR_PROTECT_KEEPUNPROTECTED == 1 // требуется установить аппаратную защиту записи после деинициализации драйвера __imp_flash_hwwrprotect_assert(); #endif #endif // Потом проверяем статус готовности if( ! (__flash_smart_waitms( _TIME_FLASHAPI_TIMEOUT ) ) ) { // устройство занято. return FLERR_UNEXPECTED_BUSY; } return FLERR_SUCCESS; } // -------------------------------------------------------------------------------------------------------- void __flash_hal__use512page(); // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__initialize - Низкоуровневая инициализация драйвера флешпамяти // // * определение наличия подключенной микросхемы // * чтение идентификатора и определение производителя // * контроль правильности: // - идентификатора производителя // - типа устройства, семейства (DevId) // - размера чипа // * установка и проверка размера страницы // // # Возвращаемое значние - код выполнения flash_err_t __flash_hal__initialize() { // если разрешено управление питанием #if AT45DB321D_POWER_MANAGEMENT // подать питание на микросхему __flash_hal__power_on(); __FLASH_WAITus( _TIME_STRUP_us ); #endif // если разрешено управление питанием #if AT45DB321D_RESET_MANAGEMENT // снять сигнлал сброса с чипа __flash_hal__reset_release(); __FLASH_WAITus( _TIME_RSTRC_us ); #endif // пробуждаем чип, если тот находится в режиме сна // иначе он не будет воспринимать команды. // Неизвестно, был ли чип в режиме гибернации, но это не важно __flash_hal__wakeup(); // предварительный таймаут запуска - ждем максимальное время до готовности записи во флеш __FLASH_WAITms( _TIME_START_ms ); // пробуем "грязное" чтение идентификатора. // Результат чтения не сохраняется, требуется обнаружить // лишь присуствие на шине и определить готовность // Поэтому как остуствие на шине, так и занятость чипа расценивается // как ошибка. flash_err_t dirty_status = __flash_hal__detect(); if( FLASH_ERROR(dirty_status) ) { // если разрешено управление сигналом сброса #if AT45DB321D_RESET_MANAGEMENT // Формируем импульс сброса: __flash_hal__reset_pulse(); #else // управление сигналом сброса недоступно // а управление питанием доступно? #if AT45DB321D_RESET_MANAGEMENT // Формируем импульс подачи питания __flash_hal__power_pulse( _TIME_COOLDOWN_ms, _TIME_START_ms ); #else // Проверка доступности вернула ошибку. // Управление питанием и сигналом сброса недоступно // Возвращаем ошибку return dirty_status; #endif #endif } // чтение регистра информации __FLASH_DWORD flashID = __flash_hal__manufactureridread( 0 ); // определяем наличие флешки по идентификатору if( ((__flash_rvid_t*) &flashID)->FullId == __FLASH_INVALID_ID ) { return FLERR_LL_INITFAIL_NOTFOUND; } // проверяем ID производителя #ifdef FLASH_DESIRED_ID if( ((__flash_rvid_t*) &flashID)->LowId != FLASH_DESIRED_ID ) { return FLERR_LL_INITFAIL_WRONGID; } #endif // проверяем вместимость чипа #ifdef FLASH_DESIRED_DENSITY if( ((__flash_rvid_t*) &flashID)->DevId.Density != FLASH_DESIRED_DENSITY ) { return FLERR_LL_INITFAIL_WRONGDENSITY; } #endif // проверяем семейство чипа #ifdef FLERR_LL_INITFAIL_WRONGFAMILY if( ((__flash_rvid_t*) &flashID)->DevId.Family != FLASH_DESIRED_FAMILY ) { return FLERR_LL_INITFAIL_WRONGFAMILY; } #endif // если разрешено управление аппаратным сигналом защиты записи #if AT45DB321D_HW_WR_PROTECT // если аппаратная защита записи отключена в настройках #if AT45DB321D_HW_WR_PROTECT_KEEPUNPROTECTED == 1 // требуется снять аппаратную защиту записи на всё время работы драйвера __imp_flash_hwwrprotect_release(); #endif #endif // определить размер страницы: если выбран AT45DB321D_EMU512, а во флешке AT45DB321D_PRM512 - лочимся // установить размер страницы если выбран AT45DB321D_PRM512 #ifdef AT45DB321D_PRM512 // выбран режим страницы 512. // перепрограммируем чип на страницы по 512 байт. // операция не отменяемая, чип программируется один раз. // проверяем текущий размер страницы. if( __fps_512 != __flash_hal__getpagesize(); { // если 528 - перепрограммируем __flash_hal__use512page(); #if AT45DB321D_BKGOPERATIONS __FLASH_SMART_WAITms(_TIME_PGPRG_ms); #endif // для изменения размера страницы по документации требуется // отключить питание чипа и подать снова. #if AT45DB321D_POWER_MANAGEMENT // если доступно управление питанием, используем его __flash_hal__power_pulse( _TIME_COOLDOWN_ms, _TIME_START_ms ); #else // если управление питанием недоступно, используем callback-процедуру пользователя // функция вызывается для отключения питания чипа в случае если программа // обнаруживает, что установлен режим не 512 байт. Сначала функция __flash_hal__use512page // переключает размер страницы, затем вызывает эту функцию. __imp_flash_powercycle(); // ожидание готовности запуска __FLASH_WAITms( _TIME_START_ms ); #endif } // # для применения нового размера требуется ОТКЛЮЧЕНИЕ ПИТАНИЯ! // проверяем текущий размер страницы. if( __fps_512 != __flash_hal__getpagesize(); { // Ошибку выдаем: просили установить 512 байт, но не сработало. return FLERR_LL_INITFAIL_PAGESIZE; } #else #ifdef AT45DB321D_EMU512 // выбран режим ЭМУЛЯЦИИ страниц по 512 байт // Если в чипе прошит размер 512 байт, то это уже не эмуляция. if( __fps_512 == __flash_hal__getpagesize() ) { // Но ошибку не выдаем, т.к. все должно работать. } #else // выбран обычный режим без эмуляции размера страницы 512 байт. // предполагается использование странцы 528 байт. if( __fps_512 == __flash_hal__getpagesize() ) { // в чипе прошит размер 512 - выдем ошибку, т.к. невозможно перенастроить чип return FLERR_LL_INITFAIL_PAGESIZE; } #endif #endif return FLERR_SUCCESS; } // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusread - чтение регистра статуса // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * НЕ задерживает выполнение void __flash_hal__statusread( __flash_status_t * pcReadRegister // буфер для чтения статус-регистра ) { chip_sel_active(); ( (__flash_packet_statusread_t*) cmdbuffer )->opcode = _ACMD_STATREAD; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statusread_t) ); // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__page_read - чтение одной страницы // // * не изменяет содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // void __flash_hal__page_read( __FLASH_WORD wPageNum, // номер страницы для чтения __FLASH_WORD wPageOfs, // адрес начала чтения в странице __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ) // количество данных на чтение { chip_sel_active(); ( (__flash_packet_pageread_t*) cmdbuffer )->opcode = _RCMD_PAGEREAD; ( (__flash_packet_pageread_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_pageread_t*) cmdbuffer )->offset = wPageOfs; ( (__flash_packet_pageread_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_pageread_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pageread_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- #ifndef AT45DB321D_EMU512 // -------------------------------------------------------------------------------------------------------- // __flash_hal__array_read - последовательное чтение (массив) // // * не изменяет содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * недоступна в режиме программной эмуляции 512-байтных страниц (AT45DB321D_EMU512) void __flash_hal__array_read ( __FLASH_WORD wPageNum, // номер начальной страницы для чтения __FLASH_WORD wPageOfs, // адрес начала чтения в начальной странице __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ) // количество данных на чтение { chip_sel_active(); ( (__flash_packet_arrayread_t*) cmdbuffer )->opcode = _RCMD_ARRYREAD; ( (__flash_packet_arrayread_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_arrayread_t*) cmdbuffer )->offset = wPageOfs; ( (__flash_packet_arrayread_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_arrayread_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_arrayread_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- #else #warning В режиме эмуляции страницы 512 байт функция последовательного чтения недоступна. // Эмуляция размера страницы в 512 байт достигается неполной записью и неполным чтением страницы микросхемы. // При этом операции чтения/записи буферизируются драйвером памяти таким образом, что для программы высокого // уровня этот процесс остается прозрачным. Однако команда последовательного чтения использует иной алгоритм // чтения: автоматическое инкрементирование указателя чтения без буферизации. Таким образом при использовании // команды последовательного чтения в режиме эмуляции на каждую читаемую страницу будет приходиться дополнительные // 16 байт мусорной информации, сохраненной в чипе, но никогда не перезаписываемой драйвером (в режиме эмуляции). // Поэтому без специальной обработки (прореживания) команда не имеет смысла - вместо прореживания используется // повторная передача адреса уже следующей страницы на чтение. Таким образом осуществляется чтение больших // объемов данных в режиме эмуляции. // // Реальное положение page N page N+1 page N+2 ...... // дел. Распределение +----------+----------+----------+ // данных по страницам. | 512 | 16 | 512 | 16 | 512 | 16 | .... // +----------+----------+----------+ // \ \ | | / / // \ \ | | / / // ---------------------------------------------------------------------------------- // \ \| |/ / // Эмуляция размера страниц +-----+-----+-----+ Так представляются страницы чипа в режиме // режим эмуляции 512 байт. | 512 | 512 | 512 | эмуляции. Однако последовательное чтение // +-----+-----+-----+ выдает 16 байтное дополнение м/у ними. // page N page N+2 // page N+1 #endif #ifdef AT45DB321D_PRM512 #ifndef AT45DB321D_EMU512 // -------------------------------------------------------------------------------------------------------- // __flash_hal__use512page - сконфигурировать чип на работу со стандартной страницей 512 байт // // # НАВСЕГДА изменяет размер страницы! // * потоко-небезопасная функция // * недоступна в режиме программной эмуляции 512-байтных страниц (AT45DB321D_EMU512) // # для применения нового размера требуется ОТКЛЮЧЕНИЕ ПИТАНИЯ! void __flash_hal__use512page() { chip_sel_active(); ( (__flash_packet_pagecnfg_t*) cmdbuffer )->opcode = _PCMD_PGSZCNFG; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pagecnfg_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms(_TIME_PGPRG_ms); #endif } #endif #endif // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer1_read - чтение буфера 1 (up to 66 MHz) // // * не изменяет содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция void __flash_hal__buffer1_read( __FLASH_WORD wBuffOfs, // адрес начала чтения в буфере __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ) // количество данных на чтение { chip_sel_active(); ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->opcode = _RCMD_BUF1READ; ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferread_fast_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer2_read - чтение буфера 2 (up to 66 MHz) // // * не изменяет содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция void __flash_hal__buffer2_read( __FLASH_WORD wBuffOfs, // адрес начала чтения в буфере __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ) // количество данных на чтение { chip_sel_active(); ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->opcode = _RCMD_BUF2READ; ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_bufferread_fast_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferread_fast_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer1_read_slow - чтение буфера 1 (up to 33 MHz) // // * не изменяет содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция void __flash_hal__buffer1_read_slow( __FLASH_WORD wBuffOfs, // адрес начала чтения в буфере __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ) // количество данных на чтение { chip_sel_active(); ( (__flash_packet_bufferread_slow_t*) cmdbuffer )->opcode = _RCMD_BUF1READ; ( (__flash_packet_bufferread_slow_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_bufferread_slow_t*) cmdbuffer )->__reserved = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferread_slow_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer2_read_slow - чтение буфера 2 (up to 33 MHz) // // * не изменяет содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция void __flash_hal__buffer2_read_slow( __FLASH_WORD wBuffOfs, // адрес начала чтения в буфере __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ) // количество данных на чтение { chip_sel_active(); ( (__flash_packet_bufferread_slow_t*) cmdbuffer )->opcode = _RCMD_BUF2READ; ( (__flash_packet_bufferread_slow_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_bufferread_slow_t*) cmdbuffer )->__reserved = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferread_slow_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer1_write - запись буфера 1 // // * ИЗМЕНЯЕТ содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция void __flash_hal__buffer1_write( __FLASH_WORD wBuffOfs, // адрес начала записи в буфере-приемнике (чип) __FLASH_BYTE * pDataWrite, // указатель на буфер-источник данных __FLASH_WORD wCntToWrite ) // количество данных на запись { chip_sel_active(); ( (__flash_packet_bufferwrite_t*) cmdbuffer )->opcode = _WCMD_BUF1WRIT; ( (__flash_packet_bufferwrite_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_bufferwrite_t*) cmdbuffer )->__reserved = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferwrite_t) ); // пишем данные __FLASH_HAL_WR( pDataWrite, wCntToWrite ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer2_write - запись буфера 2 // // * ИЗМЕНЯЕТ содержимое внутренних SRAM буферов // * не проверяет правильность переданных параметров // * потоко-небезопасная функция void __flash_hal__buffer2_write( __FLASH_WORD wBuffOfs, // адрес начала записи в буфере-приемнике (чип) __FLASH_BYTE * pDataWrite, // указатель на буфер-источник данных __FLASH_WORD wCntToWrite ) // количество данных на запись { chip_sel_active(); ( (__flash_packet_bufferwrite_t*) cmdbuffer )->opcode = _WCMD_BUF2WRIT; ( (__flash_packet_bufferwrite_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_bufferwrite_t*) cmdbuffer )->__reserved = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferwrite_t) ); // пишем данные __FLASH_HAL_WR( pDataWrite, wCntToWrite ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer1_program - программирование буфера 1 в страницу со стиранием // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__buffer1_program( __FLASH_WORD wPageNum // номер страницы, куда произвести программирование ) { chip_sel_active(); ( (__flash_packet_bufferprogram_t*) cmdbuffer )->opcode = _WCMD_BUF1PROG; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferprogram_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGEPR_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer2_program - программирование буфера 2 в страницу со стиранием // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__buffer2_program( __FLASH_WORD wPageNum // номер страницы, куда произвести программирование ) { chip_sel_active(); ( (__flash_packet_bufferprogram_t*) cmdbuffer )->opcode = _WCMD_BUF2PROG; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferprogram_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGEPR_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer1_program_wo_erase - программирование буфера 1 в страницу без стирания // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ЕДИНИЦЫ МИЛЛИСЕКУНД void __flash_hal__buffer1_program_wo_erase( __FLASH_WORD wPageNum // номер страницы, куда произвести программирование ) { chip_sel_active(); ( (__flash_packet_bufferprogram_t*) cmdbuffer )->opcode = _WCMD_BUF1PRGx; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferprogram_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__buffer2_program_wo_erase - программирование буфера 2 в страницу без стирания // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ЕДИНИЦЫ МИЛЛИСЕКУНД void __flash_hal__buffer2_program_wo_erase( __FLASH_WORD wPageNum // номер страницы, куда произвести программирование ) { chip_sel_active(); ( (__flash_packet_bufferprogram_t*) cmdbuffer )->opcode = _WCMD_BUF2PRGx; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_bufferprogram_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferprogram_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__page_erase - стирание страницы // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__page_erase( __FLASH_WORD wPageNum // номер стираемой страницы ) { chip_sel_active(); ( (__flash_packet_pageerase_t*) cmdbuffer )->opcode = _ECMD_PAGERASE; ( (__flash_packet_pageerase_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_pageerase_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_pageerase_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pageerase_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__block_erase - стирание блока // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИЛЛИСЕКУНД void __flash_hal__block_erase( __FLASH_WORD wBlockNum // номер стираемого блока ) { chip_sel_active(); ( (__flash_packet_blockerase_t*) cmdbuffer )->opcode = _ECMD_BLKERASE; ( (__flash_packet_blockerase_t*) cmdbuffer )->block = wBlockNum; ( (__flash_packet_blockerase_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_blockerase_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_blockerase_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_BKERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__sector0_erase - стирание секторов 0a и 0b // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СЕКУНДЫ void __flash_hal__sector0_erase( __FLASH_WORD wSubSector // номер подсектора 0 или 1 ) { chip_sel_active(); ( (__flash_packet_sector0erase_t*) cmdbuffer )->opcode = _ECMD_SCTERASE; ( (__flash_packet_sector0erase_t*) cmdbuffer )->subsector = wSubSector; ( (__flash_packet_sector0erase_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_sector0erase_t*) cmdbuffer )->__reserved2 = 0; ( (__flash_packet_sector0erase_t*) cmdbuffer )->__reserved3 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_sector0erase_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_SCERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__sector_erase - стирание секторов с номером 1 и выше // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СЕКУНДЫ void __flash_hal__sector_erase( __FLASH_WORD wSector // номер сектора 1-63 ) { chip_sel_active(); ( (__flash_packet_sectorerase_t*) cmdbuffer )->opcode = _ECMD_SCTERASE; ( (__flash_packet_sectorerase_t*) cmdbuffer )->sector = wSector; ( (__flash_packet_sectorerase_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_sectorerase_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_sectorerase_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_SCERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__page_write_via_buffer1 - запись страницы через буфер 1 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__page_write_via_buffer1( __FLASH_WORD wBuffOfs, // адрес начала записи в буфере-приемнике (чип) __FLASH_BYTE * pDataWrite, // указатель на буфер-источник данных __FLASH_WORD wCntToWrite, // количество данных на запись __FLASH_WORD wPageNum // номер страницы, куда произвести программирование ) { chip_sel_active(); ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->opcode = _WCMD_PGB1WRIT; ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->__reserved= 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pagewriteviabuffer_t) ); // пишем данные __FLASH_HAL_WR( pDataWrite, wCntToWrite ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGEPR_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__page_write_via_buffer2 - запись страницы через буфер 2 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__page_write_via_buffer2( __FLASH_WORD wBuffOfs, // адрес начала записи в буфере-приемнике (чип) __FLASH_BYTE * pDataWrite, // указатель на буфер-источник данных __FLASH_WORD wCntToWrite, // количество данных на запись __FLASH_WORD wPageNum // номер страницы, куда произвести программирование ) { chip_sel_active(); ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->opcode = _WCMD_PGB2WRIT; ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->offset = wBuffOfs; ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_pagewriteviabuffer_t*) cmdbuffer )->__reserved= 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pagewriteviabuffer_t) ); // пишем данные __FLASH_HAL_WR( pDataWrite, wCntToWrite ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGEPR_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__pagetobuffer1 - загрузка содержимого страницы в буфер 1 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИКРОСЕКУНД void __flash_hal__pagetobuffer1( __FLASH_WORD wPageNum // номер страницы для загрузки ) { chip_sel_active(); ( (__flash_packet_bufferload_t*) cmdbuffer )->opcode = _ACMD_BUF1LOAD; ( (__flash_packet_bufferload_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_bufferload_t*) cmdbuffer )->__reserved =0; ( (__flash_packet_bufferload_t*) cmdbuffer )->__reserved2=0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferload_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_WAITus( _TIME_BLDCM_us ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__pagetobuffer2 - загрузка содержимого страницы в буфер 2 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИКРОСЕКУНД void __flash_hal__pagetobuffer2( __FLASH_WORD wPageNum // номер страницы для загрузки ) { chip_sel_active(); ( (__flash_packet_bufferload_t*) cmdbuffer )->opcode = _ACMD_BUF2LOAD; ( (__flash_packet_bufferload_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_bufferload_t*) cmdbuffer )->__reserved =0; ( (__flash_packet_bufferload_t*) cmdbuffer )->__reserved2=0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_bufferload_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_WAITus( _TIME_BLDCM_us ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__pagetobuffer1 - сравнение содержимого страницы с буфером 1 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИКРОСЕКУНД void __flash_hal__buffer1_compare( __FLASH_WORD wPageNum // номер страницы для сравнения ) { chip_sel_active(); ( (__flash_packet_buffercompare_t*) cmdbuffer )->opcode = _ACMD_BUF1CMPR; ( (__flash_packet_buffercompare_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_buffercompare_t*) cmdbuffer )->__reserved =0; ( (__flash_packet_buffercompare_t*) cmdbuffer )->__reserved2=0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_buffercompare_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_WAITus( _TIME_BLDCM_us ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__pagetobuffer2 - сравнение содержимого страницы с буфером 2 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИКРОСЕКУНД void __flash_hal__buffer2_compare( __FLASH_WORD wPageNum // номер страницы для сравнения ) { chip_sel_active(); ( (__flash_packet_buffercompare_t*) cmdbuffer )->opcode = _ACMD_BUF2CMPR; ( (__flash_packet_buffercompare_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_buffercompare_t*) cmdbuffer )->__reserved =0; ( (__flash_packet_buffercompare_t*) cmdbuffer )->__reserved2=0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_buffercompare_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_WAITus( _TIME_BLDCM_us ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__autopagerewrite1 - обновление страницы через буфер 1 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__autopagerewrite1( __FLASH_WORD wPageNum // номер обновляемой страницы ) { chip_sel_active(); ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->opcode = _ACMD_PAGEREF1; ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_autopagerewrite_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGEPR_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__autopagerewrite2 - обновление страницы через буфер 2 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__autopagerewrite2( __FLASH_WORD wPageNum // номер обновляемой страницы ) { chip_sel_active(); ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->opcode = _ACMD_PAGEREF2; ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->page = wPageNum; ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->__reserved = 0; ( (__flash_packet_autopagerewrite_t*) cmdbuffer )->__reserved2 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_autopagerewrite_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGEPR_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__sleepmode - переход в режим пониженного энергопотребления // // * потоко-небезопасная функция // # переводит устройство в режим, когда все команды, кроме __flash_hal__wakeup игнорируются void __flash_hal__sleepmode() { chip_sel_active(); ( (__flash_packet_powerdown_t*) cmdbuffer )->opcode = _ACMD_EPWRDOWN; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_powerdown_t) ); chip_sel_inactive(); __FLASH_WAITus( _TIME_EDPDM_us ); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__wakeup - выход из режима пониженного энергопотребления // // * потоко-небезопасная функция // # выводит устройство из режима, когда все команды, кроме __flash_hal__wakeup игнорируются void __flash_hal__wakeup() { chip_sel_active(); // если флеш находилась во сне, необходимо ждать _TIME_RDPDM_us __FLASH_WAITus(_TIME_RDPDM_us); ( (__flash_packet_powerdown_t*) cmdbuffer )->opcode = _ACMD_LPWRDOWN; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_powerdown_t) ); chip_sel_inactive(); __FLASH_WAITus( _TIME_RDPDM_us ); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__manufactureridread - чтение идентификатора производителя // // * потоко-небезопасная функция // * может использоваться для опеределения типа чипа для выяснения его вместимости // * функция принимает параметр @pManufacturerID типа __flash_id_t. Этот параметр будет содержать // информацию о чипе, если параметр не NULL. Кроме того, для того, чтобы прочитать расширенную // информацию производителя (extended device information), поля pManufacturerID->pExtBf и // pManufacturerID->ExtLen должны быть проининциализированны указателем на принимающий буфер // и длинной этого буфера соответственно. При наличии расширенной информации поле ExtLen будет // перезаписано, и будет содержать длинну расширенной информации, сохраненной по указателю pExtBf. // Память по указателю pExtBf должна быть выделена заранее перед вызовом функции. Нуль-символ не // добавляется. Память, начиная с ExtLen байта, не перезаписывается (остается мусор). // * параметр @pManufacturerID может быть равен NULL. Для того, чтобы НЕ читать расширенную информацию, // передайте NULL вместо pManufacturerID, или, если передаете pManufacturerID, обнулите в нем поля pExtBf и ExtLen. // * функция способна определять расширенный Manufacturer ID согласно JEDEC JEP-106. Таким образом, кроме // стандартного ID производителя длинной 1 байт, производитель может использовать т.н. Continuation Code - 0x7F // Если стандартный код читается как 7F, функия продолжает чтение идентификатора до тех пор, пока не будет // принят байт, отличный от 7F, причем количество таких кодов 7F будет сохранено (не более 255) // и интерпретироваться как HighId. Если функция обнаружит более 255 кодов 7F, они подсчитаны не будут, при этом // HighId будет равен 255, а LowId - первый найденный не-7F код (даже после более 255 кодов 7F). // * вовзращаемое значение - DWORD, "откушенный" по младшему адресу от структуры __flash_id_t - содержит // DevId, LowId, HighId. __FLASH_DWORD __flash_hal__manufactureridread( __flash_id_t * pManufacturerID // необязательный параметр-буфер для приема расширенной информации ) { // локальные переменные функции объединены с возвращаемым значением, чтобы вернуть // часть информации в виде DWORD union { struct { __FLASH_BYTE LowId; // стандартный байт ID (не расширенный) __FLASH_BYTE HighId; // расширенный байт ID (количество 0x7F Continuation Code) (JEDEC JEP-106) union { __FLASH_WORD DevId; // код устройства struct { __FLASH_BYTE LDevId; // код устройства (Low) __FLASH_BYTE HDevId; // код устройства (High) }; }; }; __FLASH_DWORD ReturnValue; // возвращаемое значение }; DevId = 0; LDevId = 0; HDevId = 0; LowId = 0; HighId = 0; ReturnValue = 0; //----------- chip_sel_active(); //----------- ( (__flash_packet_manufactureridread_t*) cmdbuffer )->opcode = _ACMD_MFIDREAD; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_manufactureridread_t) ); //----------- // чтение Manufacturer ID do { __FLASH_HAL_RD( &LowId, sizeof( LowId ) ); if( HighId < 255 ) HighId += ( (__FLASH_MANIDEX_OPCODE == LowId)? 1 : 0 ); } while( (__FLASH_MANIDEX_OPCODE == LowId) ); //----------- // чтение Device ID __FLASH_HAL_RD( &LDevId, sizeof( LDevId ) ); __FLASH_HAL_RD( &HDevId, sizeof( HDevId ) ); //----------- // чтение расширенной информации только если нам передали структуру для заполнения if( pManufacturerID ) { // заполняем поля в переданной нам структуре pManufacturerID->DevId = DevId; // device ID pManufacturerID->LowId = LowId; // Manufacturer ID (Standart) pManufacturerID->HighId = HighId; // Manufacturer ID (Extended - Continuation Code 0x7F count) // записываем длинну расширенной информации { __FLASH_BYTE ExtLen; // читаем длинну расширенной информации __FLASH_HAL_RD( &ExtLen, sizeof( ExtLen ) ); // записываем длинну расширенной информации pManufacturerID->ExtLen = ExtLen; // если есть куда записать расширенную информацию if( pManufacturerID->pExtBf ) { // если на чипе есть расширенная информация if( ExtLen ) { // ограничиваем емкость буфера по размеру расширенной информации if( pManufacturerID->ExtLen > ExtLen ) { pManufacturerID->ExtLen = ExtLen; } // сначала считываем доступное количество байт (определяется значением ExtLen в ВЫХОДНОЙ структуре __FLASH_HAL_RD( pManufacturerID->pExtBf, sizeof( pManufacturerID->ExtLen ) ); // затем перезаписываем длинну в выходную структуру pManufacturerID->ExtLen = ExtLen; } else // нет расширенной информации { pManufacturerID->ExtLen = 0; // обнуляем длинну расширенной информации в выходной структуре } } } } //----------- chip_sel_inactive(); //----------- return ReturnValue; } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__writeprotect_enable - включить программную защиту от записи/стирания // // * потоко-небезопасная функция // # переводит устройство в режим, когда невозможно стирать/записывать некоторые секторы void __flash_hal__writeprotect_enable() { chip_sel_active(); ( (__flash_packet_protecttoggle_t*) cmdbuffer )->opcode = _SCMD_4SCTPREN; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protecttoggle_t) ); chip_sel_inactive(); // если разрешено управление аппаратным сигналом защиты записи #if AT45DB321D_HW_WR_PROTECT // если аппаратная защита записи не отключена в настройках #if AT45DB321D_HW_WR_PROTECT_KEEPUNPROTECTED == 0 // установить аппаратную защиту записи __imp_flash_hwwrprotect_assert(); #endif #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__writeprotect_disable - выключить программную защиту от записи/стирания // // * потоко-небезопасная функция // # выводит устройство из режима, когда невозможно стирать/записывать некоторые секторы (если нет аппаратной защиты) void __flash_hal__writeprotect_disable() { // если разрешено управление аппаратным сигналом защиты записи #if AT45DB321D_HW_WR_PROTECT // если аппаратная защита записи не отключена в настройках #if AT45DB321D_HW_WR_PROTECT_KEEPUNPROTECTED == 0 // снять аппаратную защиту записи __imp_flash_hwwrprotect_release(); #endif #endif chip_sel_active(); ( (__flash_packet_protecttoggle_t*) cmdbuffer )->opcode = _SCMD_4SCTPRDS; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protecttoggle_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__protectregister_erase - стирает регистр защиты, помечая ВСЕ сектора как защищенные // // * потоко-небезопасная функция // # после выдачи этой команды и последующей __flash_hal__writeprotect_enable все сектора будут защищены от записи/стирания // # если включена программная защита от записи, все операции стирания/записи для всех секторов будут заблокированы до ее отключения // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД void __flash_hal__protectregister_erase() { chip_sel_active(); ( (__flash_packet_protectregistererase_t*) cmdbuffer )->opcode = _SCMD_4PRREGER; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protectregistererase_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__protectregister_write - записывает регистр защиты // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите содержимое регистра защиты (см. __flash_protectionregister_t) // # требуется предварительное стирание! (__flash_hal__protectregister_erase) // * задерживает выполнение на МИЛЛИСЕКУНДЫ // * ИЗМЕНЯЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО БУФЕРА 1 void __flash_hal__protectregister_write( __flash_protectionregister_t * contents // содержимое регистра защиты для записи ) { if( !contents ) return; chip_sel_active(); ( (__flash_packet_protectregisterwrite_t*) cmdbuffer )->opcode = _SCMD_4PRREGWR; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protectregisterwrite_t) ); // пишем регистр защиты __FLASH_HAL_WR( contents, sizeof(__flash_protectionregister_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 //! __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__protectregister_read - прочитывает регистр защиты // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер для содержимого регистра защиты (см. __flash_protectionregister_t) void __flash_hal__protectregister_read( __flash_protectionregister_t * contents // буфер-приемник содержимого регистра защиты ) { if( !contents ) return; chip_sel_active(); ( (__flash_packet_protectregisterread_t*) cmdbuffer )->opcode = _SCMD_PRTREGRD; ( (__flash_packet_protectregisterread_t*) cmdbuffer )->__reserved = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protectregisterwrite_t) ); // читаем регистр защиты __FLASH_HAL_RD( contents, sizeof(__flash_protectionregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__sectorlockdown - постоянная блокировка сектора от записи/стирания // // * потоко-небезопасная функция // # блокирует сектор навсегда: он становится "только для чтения" // * укажите адрес, принадлежащий сектору в параметре @address // * задерживает выполнение на МИЛЛИСЕКУНДЫ void __flash_hal__sectorlockdown( __FLASH_DWORD address // адрес внутри блокируемого сектора ) { chip_sel_active(); ( (__flash_packet_sectorlockdown_t*) cmdbuffer )->opcode = _SCMD_4SCTLKDN; // заполняем адрес ( (__flash_packet_sectorlockdown_t*) cmdbuffer )->laddress = address & 0x0000FFFF; ( (__flash_packet_sectorlockdown_t*) cmdbuffer )->haddress = (address >> 16) & 0x000000FF; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_sectorlockdown_t) ); chip_sel_inactive(); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__lockdownregister_read - прочитывает регистр блокировки // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер для содержимого регистра блокировки (см. __flash_lockdownregister_t) void __flash_hal__lockdownregister_read( __flash_lockdownregister_t * contents // буфер-приемник содержимого регистра блокировки ) { if( !contents ) return; chip_sel_active(); ( (__flash_packet_lockdownregisterread_t*) cmdbuffer )->opcode = _SCMD_LKDNRGRD; ( (__flash_packet_lockdownregisterread_t*) cmdbuffer )->__reserved = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_lockdownregisterread_t) ); // читаем регистр блокировки __FLASH_HAL_RD( contents, sizeof(__flash_lockdownregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityregister_write - записывает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * ИЗМЕНЯЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО БУФЕРА 1 // * записывает только ПОЛЬЗОВАТЕЛЬСКУЮ часть // # РЕГИСТР БЕЗОПАСНОСТИ МОЖЕТ БЫТЬ ЗАПИСАН ТОЛЬКО ОДИН РАЗ! void __flash_hal__securityregister_write( __flash_usersecurityregister_t * contents // содержимое регистра безопасности (часть, доступная для записи пользователю) ) { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->opcode = _SCMD_4SECRGWR; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); // записываем регистр безопасности __FLASH_HAL_WR( contents, sizeof(__flash_usersecurityregister_t) ); #if AT45DB321D_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityregister_read - прочитывает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер-приемние для сохранения содержимого регистра блокировки (см. __flash_securityregister_t) // * считывает как пользовательскую часть, так и запрограммированную производителем void __flash_hal__securityregister_read( __flash_securityregister_t * contents // буфер-приемник содержимого регистра блокировки ) { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterread_t*) cmdbuffer )->opcode = _SCMD_4SECRGRD; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterread_t) ); // читаем регистр безопасности __FLASH_HAL_RD( contents, sizeof(__flash_securityregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityregister_read - прочитывает регистр безопасности и выполняет // проверку осмысленности прочитанного заводского идентификатора. // Функция расценивает индентификатор состоящий из одних 0xFF или 0x00 как невозможный. // В этом случае имеет место ошибка, функция возвращает false. bool __flash_hal__securityregister_validate( __flash_securityregister_t * contents // буфер-приемник содержимого регистра блокировки ) { if( NULL != contents ) { __flash_hal__securityregister_read( contents ); __FLASH_DWORD n00 = 0; __FLASH_DWORD nFF = 0; for( __FLASH_DWORD i = 0; i < __FLASH_FACT_SECURITY_BYTES; ++i ) { if( 0xFF == contents->FactoryPart.UserId[i] ) ++nFF; if( 0x00 == contents->FactoryPart.UserId[i] ) ++n00; } if( (n00 != __FLASH_FACT_SECURITY_BYTES) && (nFF != __FLASH_FACT_SECURITY_BYTES) ) { return true; } } return false; } // -------------------------------------------------------------------------------------------------------- #if AT45DB321D_POWER_MANAGEMENT > 0 // -------------------------------------------------------------------------------------------------------- // __flash_hal__power_on - реализует управление питанием микросхемы памяти (подает питание) // void __flash_hal__power_on() { // снять сигнал выбора чипа (чип не выбран, режим idle) chip_sel_inactive(); // подать питание __imp_flash_poweron(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__power_off - реализует управление питанием микросхемы памяти (снимает питание) // void __flash_hal__power_off() { // снять питание __imp_flash_poweroff(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__power_pulse - реализует управление питанием микросхемы - формирует импульс перезагрузки void __flash_hal__power_pulse( __FLASH_WORD nCooldownTime_ms, __FLASH_WORD nStartupTime_ms ) { // снять питание __imp_flash_poweroff(); // снять сигнал выбора чипа (чип не выбран, режим idle) chip_sel_inactive(); if( nCooldownTime_ms > 0 ) { // немного подождем, пока остынет :) __FLASH_WAITms( _TIME_COOLDOWN_ms ); } else { // ждем совсем немного __FLASH_WAITus( _TIME_STRUP_us ); } // подать питание __imp_flash_poweron(); // если разрешено управление режимом сброса #if AT45DB321D_RESET_MANAGEMENT // сформировать импульс сброса микросхемы __flash_hal__reset_pulse(); #endif if( nStartupTime_ms > 0 ) { // ожидать готовности __FLASH_WAITms( _TIME_START_ms ); } else { // ждем совсем немного __FLASH_WAITus( _TIME_STRUP_us ); } } #endif #if AT45DB321D_RESET_MANAGEMENT > 0 // -------------------------------------------------------------------------------------------------------- // __flash_hal__reset_assert - реализует управление сигналом сброса микросхемы памяти (устанавливает сигнал сброса) // void __flash_hal__reset_assert() { // снять сигнал выбора чипа (чип не выбран, режим idle) chip_sel_inactive(); // установить сигнал сброса __imp_flash_reset_assert(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__reset_release - реализует управление сигналом сброса микросхемы памяти (снимает сигнал сброса) // void __flash_hal__reset_release() { // снять сигнал сброса __imp_flash_reset_release(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__reset_pulse - реализует управление сигналом сброса микросхемы памяти (подает законченный импульс сброса) // void __flash_hal__reset_pulse() { // формируем импульс сброса // сначала снимаем сигнал сброса __imp_flash_reset_release(); // после снятия сигнала сброса необходимо ожидать время восстановления __FLASH_WAITus(_TIME_RSTRC_us); // потом ставим сигнал сброса __flash_hal__reset_assert(); // ожидание: требуется время для реакции на сигнал сброса __FLASH_WAITus(_TIME_RSTWD_us); // потом снова снимаем __flash_hal__reset_release(); // после снятия сигнала сброса необходимо ожидать время восстановления __FLASH_WAITus(_TIME_RSTRC_us); } #endif