// Файл с API функциями работы с FLASH-чипом AT45DB161E // v 1.61 от 14/10/19 // Автор: Сычев А. #define AT45DB161E_API_C #define AT45DB161E_APILEVEL // использование интерфейса низкоуровневых функций #include "drivers\flash\at45\config\AT45DB161E_CONF.h" #include "drivers\flash\base\flash_api_error.h" #include "drivers\flash\base\flash_api_types.h" #include "drivers\flash\base\flash_api_base.h" #include "drivers\flash\at45\lowlevel\AT45DB161E_GLOB.h" #include "drivers\flash\at45\lowlevel\AT45DB161E_LL_func.h" #include "drivers\flash\at45\common\AT45DBXXX_HAL.h" static const char AT45FLASH_TEXTUAL_DESCRIPTION[] = "AT45DB161E"; static const flash_properties_t FlashProperties_AT45DB161E = { .minAddress = AT45FLASH_MINIMUM_ADDRESS, .maxAddress = AT45FLASH_MAXIMUM_ADDRESS, .maxSectors = AT45FLASH_SECTORS, .sectorSize = (AT45FLASH_PAGES_PER_SECTOR * AT45FLASH_PAGE_SIZE), .pChipDescription = AT45FLASH_TEXTUAL_DESCRIPTION }; // flash_api_initialize - инициализация драйвера и API работы с устройством static flash_err_t flash_api_initialize( bool detectOnly ); // flash_api_getready - проверка готовности устройства (со стандартным таймаутом) static flash_err_t flash_api_getready(); // flash_api_service - функция получения общих сведений об флеш-памяти. static flash_err_t flash_api_service( flash_service_info_t si, void * pdata, __FLASH_WORD * pbufsize ); // flash_api_protect - установить защиту секторов static flash_err_t flash_api_protect( flash_api_protect_t * content ); // flash_api_protect - снять защиту секторов static flash_err_t flash_api_unprotect( flash_api_protect_t * content ); // flash_api_protect_ex - установить/снять защиту секторов static flash_err_t flash_api_protect_ex( flash_api_protect_t * content, flash_api_protect_bits mode ); // flash_api_getprotect - получить информацию о защищенных секторах. static flash_err_t flash_api_getprotect( flash_api_getprotect_t * content ); // flash_api_erase - мультирежимное стирание данных static flash_err_t flash_api_erase( flash_erase_mode_t mode, __FLASH_DWORD start, __FLASH_DWORD count ); // flash_api_write - мультирежимная запись данных по адресу static flash_err_t flash_api_write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size, flash_write_mode_t mode ); // flash_api_read - чтение данных по адресу static flash_err_t flash_api_read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ); // flash_api_sleepmode - переход в режим пониженного энергопотребления static flash_err_t flash_api_sleepmode(); // flash_api_wakeup - выход из режима пониженного энергопотребления static flash_err_t flash_api_wakeup(); // flash_api_finalize - деинициализация драйвера static flash_err_t flash_api_finalize( bool bHibernate, bool bForce ); // дескриптор API const flash_api_descriptor_t AT45DB161E_API = { .routines = { .flashInitialize = flash_api_initialize, .flashGetReady = flash_api_getready, .flashService = flash_api_service, .flashProtect = flash_api_protect, .flashUnprotect = flash_api_unprotect, .flashProtectEx = flash_api_protect_ex, .flashGetProtect = flash_api_getprotect, .flashErase = flash_api_erase, .flashWrite = flash_api_write, .flashRead = flash_api_read, .flashSleepMode = flash_api_sleepmode, .flashWakeup = flash_api_wakeup, .flashFinalize = flash_api_finalize, }, .flashProperties = &FlashProperties_AT45DB161E }; // Enter() и Return(.) - макросы блокировки ресурса в многозадачных ОС // При входе в критический участок кода - выполнение API функции - вызывается Enter(), // блокируя ресурс, при выходе - Leave() или Return(.) ( для выхода из функции ) #define Enter() { __FLASH_LOCK(); } #define Leave() { __FLASH_UNLOCK(); } #define Return(code) { __FLASH_UNLOCK(); return (code); } //#define ret __FLASH_UNLOCK(); return // Done: // flash_api_initialize(...) // Высокоуровневая инициализация памяти (установка размера страницы, установка параметров защиты секторов...) // flash_api_erase(...) // стирание памяти (блоками, страницами или секторами) // flash_api_read(...) // чтение памяти по адресу // flash_api_protect(...) // защита секторов (модификация конфигурации защищаемых секторов) // flash_api_unprotect(...) // снятие защиты (модификация конфигурации защищаемых секторов) // flash_api_service(...) // получение информации о производителе, расширенной информации, размере памяти, размере страницы, количестве секторов, блоков, страниц и т.п. // flash_api_write(...) // запись памяти по адресу // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_getready - проверка готовности устройства (со стандартным таймаутом) // // # Функция возвращает FLERR_SUCCESS, еслиу устройство готово, иначе FLERR_TIMEOUT static flash_err_t flash_api_getready() { Enter(); if( AT45_LL_Routines.smart_waitms( AT45DBXXX_API_TIMEOUT ) ) { Return(FLERR_SUCCESS); } Return(FLERR_TIMEOUT); } static flash_err_t flash_api_getready_time( __FLASH_WORD timeout ) { Enter(); if( AT45_LL_Routines.smart_waitms( timeout ) ) { Return(FLERR_SUCCESS); } Return(FLERR_TIMEOUT); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_initialize - инициализация драйвера и API работы с устройством // * Если @detectOnly=true, производится только детектирование наличия чипа! // # Функция возвращает FLERR_SUCCESS. Только в этом случае гарантируется нормальная работа. // # Функция возвращает ошибку инициализации при появлении сбоев или при непрохождении проверки (см файл конфигурации AT45DB161E_CONF.h) static flash_err_t flash_api_initialize( bool detectOnly ) { // производится определение наличия чипа на шине if( detectOnly ) { return AT45_LL_Routines.startupDetect(); } // производим нисзкоуровневую инициализацию: подаем питание и будим, проверяем наличие чипа, серию, производителя, размер... flash_err_t success = AT45_LL_Routines.initialize(); if( FLASH_ERROR(success) ) { // что-то пошло не так: ай печаль-печаль. return(success); } // отключаем защиту секторов при инициализации (общий бит защиты) success = flash_api_unprotect( NULL ); if( FLASH_ERROR(success) ) { // что-то пошло не так: ай печаль-печаль. return(success); } // считываем статус if( ! AT45_LL_Routines.smart_waitms( AT45DBXXX_API_TIMEOUT ) ) { // что-то пошло не так: ай печаль-печаль. return(success); } return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_finalize - безопасная де-инициализация драйвера // Функция завершает работу с флеш-памятью, отключаяя ее или переводя в режим гибернации // @bHibernate: булевый флаг, показывает, что нужно перевести флеш-память в режим гибернации, // если false - драйвер попытается отключить питание микросхемы, если разрешено управление питанием (AT45DBXXX_POWER_MANAGEMENT) // если false и управление питанием запрещено, будет возвращена ошибка FLERR_INVALID_PARAMETER. // @bForce: насильное выполнение финализации в случае, если флеш-память занята незаконченной операцией. // если false и драйвер детектирует незаконченную операцию, будет возвращена ошибка FLERR_UNEXPECTED_BUSY. // Если выбран режим гибернации, после выдачи команды функция проверяет, уснула ли микросхема через чтение статуса. // Если в этом случае обнаруживается, что статус все еще считывается, генерируется ошибка FLERR_GENERIC_ERROR. // Данную проверку можно отключить опцией AT45DBXXX_DONOTCHECK_HIBERNATE=1. // Внимание: проверка не реализуется если bHibernate=false. // # Функция возвращает FLERR_SUCCESS всегда, за исключением вышеописанных случаев. static flash_err_t flash_api_finalize( bool bHibernate, bool bForce ) { Enter(); // подготовка к деинициализации flash_err_t status = AT45_LL_Routines.finalize_prepare(); if( FLASH_ERROR(status) ) { // ошибка, обнаружена проблема - устройство не готово // проверяем, разрешено ли принудительное завершение? if( bForce ) { // разрешено, сначала производим сброс // доступно управление сигналом сброса? #if AT45DBXXX_RESET_MANAGEMENT // да, производим сброс чипа AT45_LL_Routines.reset_pulse(); #else // нет, а доступно управление питанием? #if AT45DBXXX_POWER_MANAGEMENT // да, производим быстрый сброс чипа по питанию AT45_LL_Routines.power_pulse( 0, 0 ); #else // нет, управление питанием тоже недоступно // возвращаем ошибку FLERR_INVALID_PARAMETER - невозможно выполнить принудительное отключение Return(FLERR_INVALID_PARAMETER); #endif #endif } else { // нет, принудительное завершение запрещено // возвращаем ошибку Return(status); } } // все нормально, продолжаем // выбран режим гибернации? if( bHibernate ) { // отправляем микросхему поспать AT45_LL_Routines.sleepmode(); #if AT45DBXXX_DONOTCHECK_HIBERNATE == 0 // проверяем, ответит ли микросхема? if( AT45_LL_Routines.smart_waitms( AT45DBXXX_API_TIMEOUT ) ) { // отвечает - бит готовности прочитался... // Может это просто подтянутый сигнал к +VCC? // попробуем по другому: if( FLASH_SUCCESS(AT45_LL_Routines.dirtyDetect()) ) { // ответила! значит точно не ложилась спать - ошибка Return(FLERR_DEVICE_MALFUNCTION); } } #endif } else { // доступно управление питанием? #if AT45DBXXX_POWER_MANAGEMENT == 0 // нет, недоступно, нечего делать, генерируем ошибку Return(FLERR_INVALID_PARAMETER); #else // Доступно, отключаем питание. AT45_LL_Routines.power_off(); // не проверяем доступность, доверяем функции отключения питания #endif } Return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_service - функция получения общих сведений об флеш-памяти. // Полный список возможных запросов приведен ниже: // ЗАПРОС РАЗМЕР ТИП ТИП ИНФОРМАИИ // БУФЕРА ЗНАЧНИЯ // fsvc_getVendorId 2 __FLASH_WORD ID производителя // fsvc_getDeviceId 2 flash_deviceid_t ID устройства // fsvc_getExtInfo * __FLASH_BYTE[] расширенную информацию производителя // fsvc_getExtInfoLen 1 __FLASH_BYTE длинну расширенной информации производителя // fsvc_getCapacity 4 __FLASH_DWORD заявляемая по документации емкость устройства (MBit-s) // fsvc_getFullCapacity 4 __FLASH_DWORD полная емкость устройства (в байтах) // fsvc_getDataCapacity 4 __FLASH_DWORD доступная емкость устройства (в байтах) // fsvc_getProtect 1 __FLASH_BYTE информацию о защите секторов (общий бит защиты 0x00 или 0x01) // fsvc_getSectorsCount 2 __FLASH_WORD количество секторов // fsvc_getPagesCount 2 __FLASH_WORD количество страниц // fsvc_getBlocksCount 2 __FLASH_WORD количество блоков // fsvc_getPageSize 2 __FLASH_WORD размер страницы // fsvc_getReadyState 1 __FLASH_BYTE готовность устройства // fsvc_getMinAddress 4 __FLASH_DWORD минимально возможный линейный адрес // fsvc_getMaxAddress 4 __FLASH_DWORD максимально возможный линейный адрес // // * Параметр @si задает тип запроса (см. flash_service_info_t) // * Параметр @pdata должен указывать на заранее выделенный буфер памяти для сохранения // получаемых данных. Размер буфера зависит от типа запроса. Параметр не может быть NULL // * Параметр @pbufsize должен указывать на размер буфера, на который указывает pdata. // Параметр не может быть 0. Значение по указателю @pbufsize не может быть 0. // При успешном выполнении функции, по указателю @pbufsize будет записано фактическое количество // записанных в буфер данных. // // * Функция НЕ ОБНУЛЯЕТ память по указателю @pdata в случае, если передан слишком большой буфер. // // # Функция вернет ошибку FLERR_INVALID_PARAMETER при некорректном запросе @si // # Функция вернет ошибку FLERR_INVALID_PARAMETER если @pdata или @bufsize равны 0. // # Функция вернет ошибку FLERR_INVALID_BUFFER если размер буфера @size не достаточен для сохранения данных // // # Функция вернет FLERR_SUCCESS при отсутствии ошибок // static flash_err_t flash_api_service( flash_service_info_t si, void * pdata, __FLASH_WORD * pbufsize ) { if( !pdata || !pbufsize || !*pbufsize ) return(FLERR_INVALID_PARAMETER); Enter(); switch( si ) { case fsvc_getVendorId: // ID производителя case fsvc_getDeviceId: // ID устройства case fsvc_getCapacity: // заявляемая по документации емкость устройства (MBit-s) case fsvc_getDataCapacity: // доступная емкость устройства case fsvc_getFullCapacity: // полная емкость устройства { __FLASH_DWORD flashID = AT45_LL_Routines.manufactureridread( 0 ); switch( si ) { case fsvc_getVendorId: if( sizeof( __FLASH_WORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((__FLASH_WORD*)(pdata)) = ((__flash_rvid_t*) &flashID)->FullId; *pbufsize = sizeof(__FLASH_WORD); Return(FLERR_SUCCESS); //------------------------- case fsvc_getDeviceId: if( sizeof( __FLASH_WORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((flash_deviceid_t*)(pdata)) = ((__flash_rvid_t*) &flashID)->DevId; *pbufsize = sizeof(__FLASH_WORD); Return(FLERR_SUCCESS); //------------------------- case fsvc_getCapacity: if( sizeof( __FLASH_DWORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((__FLASH_DWORD*)(pdata)) = __FLASH_DENSITY2CAPACITY( ((flash_deviceid_t*)&((__flash_rvid_t*) &flashID)->DevId)->Density ); *pbufsize = sizeof(__FLASH_DWORD); Return(FLERR_SUCCESS); //------------------------- case fsvc_getDataCapacity: if( sizeof( __FLASH_DWORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((__FLASH_DWORD*)(pdata)) = (AT45FLASH_MAXIMUM_ADDRESS - AT45FLASH_MINIMUM_ADDRESS); *pbufsize = sizeof(__FLASH_DWORD); Return(FLERR_SUCCESS); //------------------------- case fsvc_getFullCapacity: if( sizeof( __FLASH_DWORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((__FLASH_DWORD*)(pdata)) = (AT45FLASH_MAXIMUM_ADDRESS); *pbufsize = sizeof(__FLASH_DWORD); Return(FLERR_SUCCESS); } } break; case fsvc_getMinAddress: { if( sizeof( __FLASH_DWORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((__FLASH_DWORD*)(pdata)) = (AT45FLASH_MINIMUM_ADDRESS); *pbufsize = sizeof(__FLASH_DWORD); Return(FLERR_SUCCESS); } break; case fsvc_getMaxAddress: { if( sizeof( __FLASH_DWORD ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); *((__FLASH_DWORD*)(pdata)) = (AT45FLASH_MAXIMUM_ADDRESS); *pbufsize = sizeof(__FLASH_DWORD); Return(FLERR_SUCCESS); } break; //------------------------- case fsvc_getExtInfoLen: // длинну расширенной информации производителя case fsvc_getExtInfo: // расширенную информацию производителя { __flash_id_t mid; switch( si ) { case fsvc_getExtInfoLen: if( sizeof( __FLASH_BYTE ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); mid.pExtBf = 0; mid.ExtLen = 0; // получение ДЛИННЫ расширенной информации AT45_LL_Routines.manufactureridread( &mid ); *((__FLASH_BYTE*)(pdata)) = mid.ExtLen; *pbufsize = sizeof(__FLASH_BYTE); Return(FLERR_SUCCESS); case fsvc_getExtInfo: if( 1 * sizeof( __FLASH_BYTE ) > *pbufsize ) Return(FLERR_INVALID_BUFFER); mid.pExtBf = pdata; mid.ExtLen = *pbufsize; // получение расширенной информации AT45_LL_Routines.manufactureridread( &mid ); *pbufsize = mid.ExtLen; Return(FLERR_SUCCESS); } } Return(FLERR_INVALID_BUFFER); case fsvc_getReadyState: // готовность устройства { if( sizeof( __FLASH_BYTE ) <= *pbufsize ) { *((__FLASH_BYTE*)(pdata)) = ( FLASH_SUCCESS( AT45_LL_Routines.getreadyfast() ) )? 0x01: 0x00; *pbufsize = sizeof(__FLASH_BYTE); Return(FLERR_SUCCESS); } } Return(FLERR_INVALID_BUFFER); case fsvc_getProtect: // информацию о защите секторов { if( sizeof( __FLASH_BYTE ) <= *pbufsize ) { flash_err_t status = flash_api_getprotect(0); switch( status ) { case FLERR_PROTECT_DISABLED: *pbufsize = sizeof(__FLASH_BYTE); *((__FLASH_BYTE*)(pdata)) = 0; Return(FLERR_SUCCESS); case FLERR_PROTECT_ENABLED: *pbufsize = sizeof(__FLASH_BYTE); *((__FLASH_BYTE*)(pdata)) = 1; Return(FLERR_SUCCESS); } Return(status); // Ошибка? } } Return(FLERR_INVALID_BUFFER); case fsvc_getPageSize: // размер страницы { if( sizeof( __FLASH_WORD ) >= *pbufsize ) { *((__FLASH_WORD*)(pdata)) = AT45FLASH_PAGE_SIZE; *pbufsize = sizeof(__FLASH_WORD); Return(FLERR_SUCCESS); } } Return(FLERR_INVALID_BUFFER); case fsvc_getSectorsCount: // количество секторов { if( sizeof( __FLASH_WORD ) <= *pbufsize ) // 16.04.19 Bug Fixed: changed condition ">=" to "<=" { *((__FLASH_WORD*)(pdata)) = AT45FLASH_SECTORS; *pbufsize = sizeof(__FLASH_WORD); Return(FLERR_SUCCESS); } } Return(FLERR_INVALID_BUFFER); case fsvc_getPagesCount: // количество страниц { if( sizeof( __FLASH_WORD ) >= *pbufsize ) { *((__FLASH_WORD*)(pdata)) = AT45FLASH_PAGES; *pbufsize = sizeof(__FLASH_WORD); Return(FLERR_SUCCESS); } } Return(FLERR_INVALID_BUFFER); case fsvc_getBlocksCount: // количество блоков { if( sizeof( __FLASH_WORD ) >= *pbufsize ) { *((__FLASH_WORD*)(pdata)) = AT45FLASH_BLOCKS; *pbufsize = sizeof(__FLASH_WORD); Return(FLERR_SUCCESS); } } Return(FLERR_INVALID_BUFFER); } Return(FLERR_INVALID_PARAMETER); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_protect_ex - установить/снять защиту секторов // Поробности см. описание flash_api_protect() / flash_api_unprotect() // // @mode: flash_sector_unprotected - вызов из flash_api_unprotect() // @mode: flash_sector_protected - вызов из flash_api_protect() // static flash_err_t flash_api_protect_ex( flash_api_protect_t * content, flash_api_protect_bits mode ) { Enter(); // проверяем устройство на занятость if( FLERR_TIMEOUT == flash_api_getready() ) Return(FLERR_TIMEOUT); // проверяем на NULL переданный параметр if( !content ) { if( mode == flash_sector_unprotected ) { // параметр NULL - значит СНИМАЕМ общий бит защиты AT45_LL_Routines.writeprotect_disable(); // проверяем, сборсился ли бит защиты if( AT45_LL_Routines.getprotectstate() != FLERR_PROTECT_DISABLED ) Return(FLERR_GENERIC_ERROR); } else { // параметр NULL - значит УСТАНАВЛИВАЕМ общий бит защиты AT45_LL_Routines.writeprotect_enable(); // проверяем, установился ли бит защиты if( AT45_LL_Routines.getprotectstate() != FLERR_PROTECT_ENABLED ) Return(FLERR_GENERIC_ERROR); } Return(FLERR_SUCCESS); } else { // режим модификации общего бита защиты switch( content->protection_modify ) { case flash_sector_protect_nomodify: // не трогаем общий бит защиты break; case flash_sector_protect_modify: // flash_sector_protected if( content->protection_enabled ) { // устанавливаем защиту AT45_LL_Routines.writeprotect_enable(); if( AT45_LL_Routines.getprotectstate() != FLERR_PROTECT_ENABLED ) Return(FLERR_GENERIC_ERROR); } // flash_sector_unprotected else { // снимаем защиту AT45_LL_Routines.writeprotect_disable(); if( AT45_LL_Routines.getprotectstate() != FLERR_PROTECT_DISABLED ) Return(FLERR_GENERIC_ERROR); } break; default: // неправильный параметр в поле protection_modify Return(FLERR_INVALID_PARAMETER); } // получаем указатель на буфер драйвера __flash_protectionregister_t * pReg = AT45_LL_Routines.internal_getbuffer_protect(); // зануляем память __FLASH_ZEROMEMORY( pReg, sizeof(__flash_protectionregister_t) ); // считываем байты защиты AT45_LL_Routines.protectregister_read( pReg ); //------------------------------------------------------ // модифицируем значения регистра защиты // индивидуально для сектора 0a,0b if( content->sectors.s0 ) // flash_sector_protect_pick { // сектор выбран: устанавливаем или снимаем биты защиты if( mode == flash_sector_unprotected ) { pReg->Sector0.prot_0a = __FLASH_PROTECTION_REG_S0_DISABLE; pReg->Sector0.prot_0b = __FLASH_PROTECTION_REG_S0_DISABLE; } else { pReg->Sector0.prot_0a = __FLASH_PROTECTION_REG_S0_ENABLE; pReg->Sector0.prot_0b = __FLASH_PROTECTION_REG_S0_ENABLE; } pReg->Sector0.reserved= 0; } else { /* не модифицировать статус защиты сектора */ } // модифицируем байты защиты for( int s = 1; s < __SECTORS_TYPICAL; ++s ) { if( (content->sectors.bytes[ s/8 ]) & ( 1<<(s%8)) ) { // сектор выбран: устанавливаем или снимаем биты защиты if( mode == flash_sector_unprotected ) pReg->Sectors[ s ] = __FLASH_PROTECTION_REG_DISABLE; else pReg->Sectors[ s ] = __FLASH_PROTECTION_REG_ENABLE; } else { /* не модифицировать статус защиты сектора */ } } //------------------------------------------------------ // // стираем регистр защиты AT45_LL_Routines.protectregister_erase(); // проверяем готовность устройства #if AT45DB161E_BKGOPERATIONS if( FLERR_TIMEOUT == flash_api_getready_time( _TIME_PGERS_ms ) ) #else if( FLERR_TIMEOUT == flash_api_getready() ) #endif { // фатальная ошибка: регистр защиты стерт // устройство занято. продолжать не можем // // для восстановления регистра защиты необходимо // вызвать функцию flash_error_restore() // Return(FLERR_UNEXPECTED_BUSY); } // записываем регистр защиты AT45_LL_Routines.protectregister_write( pReg ); //------------------------------------------------------ // // проверяем готовность устройства #if AT45DB161E_BKGOPERATIONS if( FLERR_TIMEOUT == flash_api_getready_time( _TIME_PGPRG_ms ) ) #else if( FLERR_TIMEOUT == flash_api_getready() ) #endif { // Ошибка: запись длится дольше положенного времени Return(FLERR_TIMEOUT); } //------------------------------------------------------ { // №№№№№№ ПРОВЕРКА №№№№№№ // считываем байты защиты AT45_LL_Routines.protectregister_read( pReg ); // индивидуально для сектора 0a,0b if( content->sectors.s0 ) // flash_sector_protect_pick { // сектор выбран: проверяем биты защиты if( mode == flash_sector_unprotected ) { if( pReg->Sector0.prot_0a != __FLASH_PROTECTION_REG_S0_DISABLE || pReg->Sector0.prot_0b != __FLASH_PROTECTION_REG_S0_DISABLE ) { Return(FLERR_GENERIC_ERROR); } } else { if( pReg->Sector0.prot_0a != __FLASH_PROTECTION_REG_S0_ENABLE || pReg->Sector0.prot_0b != __FLASH_PROTECTION_REG_S0_ENABLE ) { Return(FLERR_GENERIC_ERROR); } } } // проверяем байты защиты for( int s = 1; s < __SECTORS_TYPICAL; ++s ) { if( (content->sectors.bytes[ s/8 ]) & ( 1<<(s%8)) ) { // сектор выбран: проверяем биты защиты if( mode == flash_sector_unprotected ) { if( pReg->Sectors[ s ] != __FLASH_PROTECTION_REG_DISABLE ) Return(FLERR_GENERIC_ERROR); } else { if( pReg->Sectors[ s ] != __FLASH_PROTECTION_REG_ENABLE ) Return(FLERR_GENERIC_ERROR); } } } } //------------------------------------------------------ // успех. Return(FLERR_SUCCESS); } } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_protect - установить защиту секторов // // Функция модифицирует флаги защиты сектров выбранных пользователем в состояние "защищен". // Установите соответствующие флаги в структуре @content в состояние "1" для защиты сектора. // Функция также может модифицировать общий флаг защиты выбранных секторов. Для этого установите // желаемое состояние защиты в поле protection_enabled ( 0 - не защищено, 1 - защищено ) и установите поле // protection_modify в состояние "flash_sector_protect_modify" для того, чтобы общий флаг защиты был // изменен. // // * Для того, чтобы модифицировать только флаги защиты секторов без изменения общего флага защиты, // установите поле protection_modify в состояние "flash_sector_protect_nomodify". // // * параметр @content может быть равен NULL // // * Для того, чтобы модифицировать только общий бит защиты // БЕЗ модификации частных флагов защиты сектров: // - Для УСТАНОВКИ общего бита защиты передайте NULL вместо параметра @content // - Для УСТАНОВКИ/СНЯТИЯ общего бита защиты установите ВСЕ поля частных флагов защиты // секторов (s0...s63) в состояние flash_sector_protect_nomodify, поле protection_modify // установите в "flash_sector_protect_modify", а поле protection_enabled в желаемое // состояние флага защиты: flash_sector_protected или flash_sector_unprotected // // # Функция вернет FLERR_SUCCESS, если в процессе операции не произошло ошибок. // # Функция вернет FLERR_INVALID_PARAMETER в случае, если обнаружит ошибку в переданном параметре // # Функция вернет FLERR_UNEXPECTED_BUSY в случае, если процесс выполнения был прерван из-за неожиданного отказа устройства // # Функция вернет FLERR_GENERIC_ERROR в случае, если общий бит защиты не был установлен из-за ошибки // # Функция вернет FLERR_GENERIC_ERROR в случае, если хотя бы один из выбранных битов защиты не был установлен/сброшен // static flash_err_t flash_api_protect( flash_api_protect_t * content ) { return( flash_api_protect_ex( content, flash_sector_protected )); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_unprotect - снять защиту секторов. Функция аналогичная flash_api_protect(), // только имеет обратный эффект - снятие защиты с выбранных секторов. // // Функция модифицирует флаги защиты сектров выбранных пользователем в состояние "не защищен". // Установите соответствующие флаги в структуре @content в состояние "1" для снятия защиты сектора. // Функция также может модифицировать общий флаг защиты выбранных секторов. Для этого установите // желаемое состояние защиты в поле protection_enabled ( 0 - не защищено, 1 - защищено ) и установите поле // protection_modify в состояние "flash_sector_protect_modify" для того, чтобы общий флаг защиты был // изменен. // // * Для того, чтобы модифицировать только флаги защиты секторов без изменения общего флага защиты, // установите поле protection_modify в состояние "flash_sector_protect_nomodify". // // * параметр @content может быть равен NULL // // * Для того, чтобы модифицировать только общий бит защиты // БЕЗ модификации частных флагов защиты сектров: // - Для СНЯТИЯ общего бита защиты передайте NULL вместо параметра @content // - Для УСТАНОВКИ/СНЯТИЯ общего бита защиты установите ВСЕ поля частных флагов защиты // секторов (s0...s63) в состояние flash_sector_protect_nomodify, поле protection_modify // установите в "flash_sector_protect_modify", а поле protection_enabled в желаемое // состояние флага защиты: flash_sector_protected или flash_sector_unprotected // // # Функция вернет FLERR_SUCCESS, если в процессе операции не произошло ошибок. // # Функция вернет FLERR_INVALID_PARAMETER в случае, если обнаружит ошибку в переданном параметре // # Функция вернет FLERR_UNEXPECTED_BUSY в случае, если процесс выполнения был прерван из-за неожиданного отказа устройства // # Функция вернет FLERR_GENERIC_ERROR в случае, если общий бит защиты не был установлен из-за ошибки // # Функция вернет FLERR_GENERIC_ERROR в случае, если хотя бы один из выбранных битов защиты не был установлен/сброшен // static flash_err_t flash_api_unprotect( flash_api_protect_t * content ) { return( flash_api_protect_ex( content, flash_sector_unprotected )); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_getprotect - получить информацию о защищенных секторах. // * Указатель @content может быть NULL. // # Возвращаемое значение - общий бит защиты protection_enabled. // Если защита установлена - будет возвращен код FLERR_PROTECT_ENABLED // Если защита снята - будет возвращен код FLERR_PROTECT_DISABLED // Если указатель @content не NULL, по адресу будет записана структура типа flash_api_getprotect_t, // содержащая информацию о защите сектора (один сектор на один бит), а поле protection_enabled // будет содержать общий бит защиты - flash_sector_protected (установлена) или flash_sector_unprotected (снята). static flash_err_t flash_api_getprotect( flash_api_getprotect_t * content ) { Enter(); __flash_status_t status; // пользователь хочет получить детализацию по защите секторов if( content ) { if( FLERR_TIMEOUT == flash_api_getready() ) Return(FLERR_TIMEOUT); // получаем указатель на буфер драйвера __flash_protectionregister_t * pReg = AT45_LL_Routines.internal_getbuffer_protect(); // зануляем память __FLASH_ZEROMEMORY( pReg, sizeof(__flash_protectionregister_t) ); // считываем байты защиты AT45_LL_Routines.protectregister_read( pReg ); if( pReg->Sector0.prot_0a == __FLASH_PROTECTION_REG_S0_ENABLE || pReg->Sector0.prot_0b == __FLASH_PROTECTION_REG_S0_ENABLE ) content->sectors.s0 = 1; else content->sectors.s0 = 0; for( int s = 1; s < __SECTORS_TYPICAL; ++s ) { if( pReg->Sectors[ s ] == __FLASH_PROTECTION_REG_ENABLE ) content->sectors.bytes[ s/8 ] |= ( 1<<(s%8) ); else content->sectors.bytes[ s/8 ] &= ~( 1<<(s%8) ); } } AT45_LL_Routines.statusread(&status); if( status.bProtect ) { if( NULL != content ) // fixed: 22/05/19 content->protection_enabled = flash_sector_protected; Return(FLERR_PROTECT_ENABLED); } if( NULL != content ) // fixed: 22/05/19 content->protection_enabled = flash_sector_unprotected; Return(FLERR_PROTECT_DISABLED); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_erase - мультирежимное стирание данных // * Параметр @mode задает режим стирания: // mode==fem_byaddress - начальное смещение задается адресом в параметре @start, длинна отрезка - @count в байтах // При этом минимальный стираемый диапазон - размер страницы. // Страница, которой принадлежит адрес @start стирается полностью // Страница, которой принадлежит адрес @start + @count также стирается полность // @start не может быть меньше AT45FLASH_MINIMUM_ADDRESS // mode==fem_bypage - начальное смещение задается номером страницы в параметре @start. // Количество стираемых страниц задается параметром @count // @start не может быть меньше AT45FLASH_PAGES_PER_SECTOR // // mode==fem_byblock - начальное смещение задается номером блока в параметре @start // Количество стираемых блоков задается параметром @count // @start не может быть меньше AT45FLASH_BLOCKS_PER_SECTOR // // mode==fem_bysector - начальное смещение задается номером сектора в параметре @start // Количество стираемых секторов задается параметром @count. // @start не может быть равен 0. // // Адресное пространство с 0 по AT45FLASH_MINIMUM_ADDRESS является зарезервированным. Попытка стирания элементов // в этом диапазоне приведет к ошибке. // // * Параметр @count не может быть 0. // Параметр @start не должен указывать на зарезервированную область. // // ! Функция НЕ проверяет защиту секторов ! // // # Функция возвращает FLERR_SUCCESS если не произошло ошибок. // # Функция вернет FLERR_INVALID_PARAMETER если @start указывает на зарезервированную область. // # Функция вернет FLERR_INVALID_PARAMETER если диапазон стирания выходит за границу адресного пространства // # Функция вернет FLERR_INVALID_PARAMETER если @count равняется 0. // # Функция вернет FLERR_INVALID_PARAMETER если @mode имеет значение, отличное от перечисленных. // # Функция вернет FLERR_UNEXPECTED_BUSY если во время операции устройство перестало отвечать // static flash_err_t flash_api_erase( flash_erase_mode_t mode, __FLASH_DWORD start, __FLASH_DWORD count ) { if( !count || !start ) return(FLERR_INVALID_PARAMETER); Enter(); switch( mode ) { case fem_byaddress: // стирание по адресу if( start < AT45FLASH_MINIMUM_ADDRESS ) Return(FLERR_INVALID_PARAMETER); if( start + count > AT45FLASH_MAXIMUM_ADDRESS ) Return(FLERR_INVALID_PARAMETER); case fem_bypage: // стирание по страницам { __FLASH_DWORD PagesToErase=0; __FLASH_DWORD PageBegin =0; if( mode == fem_byaddress ) { // стирание по адресу PagesToErase = __FLASH_PAGESINRANGE( start , count ); PageBegin = __FLASH_ADDRESS2PAGE( start ); } else { // стирание по страницам if( start < AT45FLASH_PAGES_PER_SECTOR ) Return(FLERR_INVALID_PARAMETER); if( start + count > __FULL_PAGES ) Return(FLERR_INVALID_PARAMETER); PagesToErase = count; PageBegin = start; } while( PagesToErase ) { // проверяем, нельзя ли использовать блочное стирание? if( __FLASH_PAGE_ARRAGED_BY_BLOCK ( PageBegin ) && // проверяем выравниваение ( PagesToErase >= AT45FLASH_PAGES_PER_BLOCK ) ) // проверяем количество страниц { // можно! // стираем блок - это быстрее AT45_LL_Routines.block_erase( __FLASH_PAGE2BLOCK( PageBegin ) ); #if AT45DB161E_BKGOPERATIONS if( FLERR_TIMEOUT == flash_api_getready_time( _TIME_BKERS_ms ) ) #else if( FLERR_TIMEOUT == flash_api_getready() ) #endif { // фатальная ошибка: устройство занято дольше обычного Return(FLERR_UNEXPECTED_BUSY); } PageBegin += __PAGES_PER_BLOCK; PagesToErase -= __PAGES_PER_BLOCK; } else { // нельзя AT45_LL_Routines.page_erase( PageBegin ); #if AT45DB161E_BKGOPERATIONS if( FLERR_TIMEOUT == flash_api_getready_time( _TIME_PGERS_ms ) ) #else if( FLERR_TIMEOUT == flash_api_getready() ) #endif { // фатальная ошибка: устройство занято дольше обычного Return(FLERR_UNEXPECTED_BUSY); } PageBegin ++; PagesToErase --; } } } break; case fem_byblock: // стирание по блокам { if( start < AT45FLASH_PAGES_PER_SECTOR ) Return(FLERR_INVALID_PARAMETER); if( start + count > __BLOCKS ) Return(FLERR_INVALID_PARAMETER); while( count ) { AT45_LL_Routines.block_erase( start ); #if AT45DB161E_BKGOPERATIONS if( FLERR_TIMEOUT == flash_api_getready_time( _TIME_BKERS_ms ) ) #else if( FLERR_TIMEOUT == flash_api_getready() ) #endif { // фатальная ошибка: устройство занято дольше обычного Return(FLERR_UNEXPECTED_BUSY); } start ++; count --; } } break; case fem_bysector: // стирание по секторам { if( start == 0 ) Return(FLERR_INVALID_PARAMETER); // сектор 0 - зарезервирован if( start + count > __SECTORS ) Return(FLERR_INVALID_PARAMETER); while( count ) { AT45_LL_Routines.sector_erase( start ); #if AT45DB161E_BKGOPERATIONS if( FLERR_TIMEOUT == flash_api_getready_time( _TIME_SCERS_ms ) ) #else if( FLERR_TIMEOUT == flash_api_getready() ) #endif { // фатальная ошибка: устройство занято дольше обычного Return(FLERR_UNEXPECTED_BUSY); } start ++; count --; } } break; default: Return(FLERR_INVALID_PARAMETER); } // успех. Return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_write - мультирежимная запись данных по адресу // // * Параметр @address указывает линейный адрес в адресном пространстве чипа. // Область 0 - AT45FLASH_MINIMUM_ADDRESS является зарезервированной, все попытки записи в эту область вызовут ошибку. // * Параметр @pBuffer - должен указывать на буфер-источник данных для записи. Не может быть NULL. // * Параметр @size - должен указывать на размер данных на запись. Не может быть равен 0. // * Параметр @mode - задает режим записи. Доступны следующий режимы: // - fwm_safewrite - режим безопасной записи. Медленный режим, когда запись/стирание происходит // постранично с верификацией. В случае ошибки верификации запись прекращается, // остальная (незаписанная) часть данных не переписывается/не стрирается, // При этом функция возвращает ошибку FLERR_VERIFY_ERROR // // - fwm_fastwrite - режим быстрой записи. Стирание происходит по блокам (8 станиц, см. заголовочный файл) // Запись постраничная. Верификация данных не проводится. // // - fwm_compatible режим ускоренной записи. НЕ РЕАЛИЗОВАН. ИСПОЛЬЗУЕТСЯ fwm_fastwrite. // Нечто среднее между режимамаи безопасной и быстрой записи. // Стирание происходит по блокам, запись по страницам. По завершении записи/стирания // всего объема данных происходит верификация. При обнаружении ошибки возвращается код FLERR_VERIFY_ERROR. // // // # Функция возвращает FLERR_SUCCESS, если не произшло никаких ошибок. // # Функция возвращает FLERR_UNEXPECTED_BUSY, если во время записи произошел отказ устройства. // # Функция возвращает FLERR_VERIFY_ERROR, если обнаружена ошибка верификации данных. // # Функция возвращает FLERR_INVALID_PARAMETER, если указан неверный параметр: // - @address указывает на зарезервированную область, либо область записи выходит за границу адресного пространства; // - @pBuffer или @size равны 0; // - @mode имеет значение, отличное от перечисленных // // # Для быстрой работы требует включения режима AT45DB161E_BKGOPERATIONS // Функция использует три различные монорежимные функции записи: static flash_err_t flash_write_fast( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ); static flash_err_t flash_write_safe( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ); static flash_err_t flash_write_comp( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ); static flash_err_t flash_api_write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size, flash_write_mode_t mode ) { if( address < AT45FLASH_MINIMUM_ADDRESS ) return(FLERR_INVALID_PARAMETER); if( !size || !pBuffer ) return(FLERR_INVALID_PARAMETER); if( address + size > AT45FLASH_MAXIMUM_ADDRESS ) return(FLERR_INVALID_PARAMETER); switch( mode ) { case fwm_safewrite: //режим безопасной записи. // > Данные страницы прочитываются в буфер 1 чипа ( если запись страницы неполная ) // > Данные страницы прочитываются в буфер 2 чипа ( если запись страницы неполная ) // > Производится модификация данных в буфере 1 (запись в буфер со смещением) // > Используется команда стирание+запись страницы (буфер 1) // > Производится модификация данных в буфере 2 (пока идет запись) // > Производится сравнение записанной страницы с буфером 2 // > Если данные совпадают - запись без ошибок /* ______________________ / \ | Slow Moderate Fast | | \ | / | | \ | | \ | | \ | | __\____ | \_____________________/ */ return(flash_write_safe( address, pBuffer, size )); case fwm_compatible: //режим ускоренной записи // > Данные блока считываются во временный буфер контроллера // > Производится стирание блока // > Пока блок стирается, модифицируем данные в буфере // > Постранично записываем данные в чип // > Поочередно загружаем в буфер 1 и буфер 2 страницы для сравнения // > Пока один буфер производит сравнение, записываем данные во второй // > При обнаружении расхождения генерируется ошибка /* ______________________ / \ | Slow Moderate Fast | | \ | / | | | | | | | | | | | ___|___ | \_____________________/ */ return(flash_write_comp( address, pBuffer, size )); case fwm_fastwrite: //режим быстрой записи. // > Данные страницы прочитываются в буфер 1 чипа ( если запись страницы неполная ) // > Если возможно, производится стирание блока // > Пока блок стирается, модифицируем данные в буфере 1 // > Постранично записываем данные в чип (если требуется, стриание+запись) // > Готово. /* ______________________ / \ | Slow Moderate Fast | | \ | / | | / | | / | | / | | _____/_ [!] | \_____________________/ */ return(flash_write_fast( address, pBuffer, size )); default:; } return(FLERR_INVALID_PARAMETER); } //---------- // flash_write_safe() - обеспечивает режим записи fwm_safewrite // # НЕ ПРОВЕРЯЕТ ПЕРЕДАННЫЕ ПАРАМЕТРЫ // # Для быстрой работы требует включения режима AT45DB161E_BKGOPERATIONS static flash_err_t flash_write_safe( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // > Данные страницы прочитываются в буфер 1 чипа ( если запись страницы неполная ) // > Данные страницы прочитываются в буфер 2 чипа ( если запись страницы неполная ) // > Производится модификация данных в буфере 1 (запись в буфер со смещением) // > Используется команда стирание+запись страницы (буфер 1) // > Производится модификация данных в буфере 2 (пока идет запись) // > Производится сравнение записанной страницы с буфером 2 // > Если данные совпадают - запись без ошибок __FLASH_DWORD pageBegin = __FLASH_ADDRESS2PAGE( address ); // вычисляем номер первой страницы __FLASH_DWORD PagesToWrite = __FLASH_PAGESINRANGE( address, size ); // вычисляем количество затрагиваемых страниц __FLASH_DWORD BytesToWrite = __FLASH_DATAREMAININGINPAGE( address ); // вычисляем для первой страницы Enter(); do { //--------------------- // ПЕРВАЯ и ПОСЛЕДНЯЯ страницы могут записываться частично: требуется предварительное чтение if( __FLASH_ADDRESSOFFSETPAGE( address ) || PagesToWrite<=1 ) { // Данные страницы прочитываются в буфер 1 чипа AT45_LL_Routines.pagetobuffer1( pageBegin ); #if AT45DB161E_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif if( FLASH_ERROR( AT45_LL_Routines.getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); // Данные страницы прочитываются в буфер 2 чипа AT45_LL_Routines.pagetobuffer2( pageBegin ); #if AT45DB161E_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif if( FLASH_ERROR( AT45_LL_Routines.getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); } //--------------------- if( size < BytesToWrite ) BytesToWrite = size; //--------------------- // Производится модификация данных в буфере 1 (запись в буфер со смещением) AT45_LL_Routines.buffer1_write( __FLASH_ADDRESSOFFSETPAGE( address ), // смещение в буфере pBuffer, // данные BytesToWrite ); // количество данных на запись //--------------------- // идет запись: СТИРАНИЕ + ПРОГРАММИРОВАНИЕ AT45_LL_Routines.buffer1_program( pageBegin ); #if AT45DB161E_BKGOPERATIONS == 0 if( FLASH_ERROR( AT45_LL_Routines.getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // Производится модификация данных в буфере 2 (запись в буфер со смещением) AT45_LL_Routines.buffer2_write( __FLASH_ADDRESSOFFSETPAGE( address ), // смещение в буфере pBuffer, // данные BytesToWrite ); // количество данных на запись //--------------------- // дожидаемся завершения записи #if AT45DB161E_BKGOPERATIONS if( FLASH_ERROR( flash_api_getready_time( _TIME_PGEPR_ms ) ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // Производится сравнение записанной страницы с буфером 2 AT45_LL_Routines.buffer1_compare( pageBegin ); #if AT45DB161E_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif //--------------------- // Если данные совпадают - запись без ошибок if( FLASH_ERROR( AT45_LL_Routines.getcompareresult() ) ) Return(FLERR_VERIFY_ERROR); //--------------------- pageBegin++; address += BytesToWrite; pBuffer += BytesToWrite; size -= BytesToWrite; BytesToWrite = __FLASH_DATAREMAININGINPAGE( address ); } while( --PagesToWrite ); Return(FLERR_SUCCESS); } //---------- // flash_write_safe() - обеспечивает режим записи fwm_fastwrite // # НЕ ПРОВЕРЯЕТ ПЕРЕДАННЫЕ ПАРАМЕТРЫ // # Для быстрой работы требует включения режима AT45DB161E_BKGOPERATIONS static flash_err_t flash_write_fast( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // > Данные страницы прочитываются в буфер 1 чипа ( если запись страницы неполная ) // > Если возможно, производится стирание блока // > Пока блок стирается, модифицируем данные в буфере 1 // > Постранично записываем данные в чип (если требуется, стриание+запись) // > Готово. __FLASH_DWORD pageBegin = __FLASH_ADDRESS2PAGE( address ); // вычисляем номер первой страницы __FLASH_DWORD PagesToWrite = __FLASH_PAGESINRANGE( address, size ); // вычисляем количество затрагиваемых страниц __FLASH_DWORD BytesToWrite = __FLASH_DATAREMAININGINPAGE( address ); // вычисляем для первой страницы __FLASH_DWORD PagesErased = 0; // количество заранее стретых страниц (блочное стирание) Enter(); do { //--------------------- // ПЕРВАЯ и ПОСЛЕДНЯЯ страницы могут записываться частично: требуется предварительное чтение if( __FLASH_ADDRESSOFFSETPAGE( address ) || PagesToWrite<=1 ) { // Данные страницы прочитываются в буфер 1 чипа AT45_LL_Routines.pagetobuffer1( pageBegin ); #if AT45DB161E_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif if( FLASH_ERROR( AT45_LL_Routines.getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); } //--------------------- if( size < BytesToWrite ) BytesToWrite = size; //--------------------- // Производится стирание блока if( __FLASH_PAGE_ARRAGED_BY_BLOCK( pageBegin ) && PagesToWrite >= AT45FLASH_PAGES_PER_BLOCK ) { AT45_LL_Routines.block_erase( __FLASH_PAGE2BLOCK( pageBegin ) ); PagesErased = AT45FLASH_PAGES_PER_BLOCK; // запоминаем, что много-много страниц стерто } //--------------------- // Производится модификация данных в буфере 1 (запись в буфер со смещением) AT45_LL_Routines.buffer1_write( __FLASH_ADDRESSOFFSETPAGE( address ), // смещение в буфере pBuffer, // данные BytesToWrite ); // количество данных на запись #if AT45DB161E_BKGOPERATIONS //--------------------- // дожидаемся окончания стирания блока if( AT45FLASH_PAGES_PER_BLOCK == PagesErased ) // Только если только что стерли. if( FLASH_ERROR( flash_api_getready_time( _TIME_BKERS_ms ) ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // если стерто много страниц (блочное стирание ) if( PagesErased ) // идет запись: ПРОГРАММИРОВАНИЕ БЕЗ СТИРАНИЯ { AT45_LL_Routines.buffer1_program_wo_erase( pageBegin ); PagesErased--; } else // идет запись: СТИРАНИЕ + ПРОГРАММИРОВАНИЕ AT45_LL_Routines.buffer1_program( pageBegin ); #if AT45DB161E_BKGOPERATIONS == 0 if( FLASH_ERROR( AT45_LL_Routines.getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // дожидаемся завершения записи #if AT45DB161E_BKGOPERATIONS if( FLASH_ERROR( flash_api_getready_time( _TIME_PGEPR_ms ) ) ) Return(FLERR_UNEXPECTED_BUSY); #endif // *************************************************************** // * NOTE: строго говоря, можно было еще больше соптимизировать * // * и записывать в свободный второй буфер во время записи пер- * // * вого. Но это потребует переключения команд записи страниц * // * ( __flash_hal__buffer1_program_wo_erase и * // * __flash_hal__buffer1_program), а также команд записи * // * в буфер __flash_hal__pagetobuffer1, на ходу, потребуется * // * запоминать, какой буфер свободен. * // * В целях упрощения решено так не делать. * // *************************************************************** pageBegin++; address += BytesToWrite; pBuffer += BytesToWrite; size -= BytesToWrite; BytesToWrite = __FLASH_DATAREMAININGINPAGE( address ); } while( --PagesToWrite ); Return(FLERR_SUCCESS); } //---------- // flash_write_safe() - обеспечивает режим записи fwm_compatible // # НЕ ПРОВЕРЯЕТ ПЕРЕДАННЫЕ ПАРАМЕТРЫ // # Для быстрой работы требует включения режима AT45DB161E_BKGOPERATIONS // // # РЕЖИМ НЕ РЕАЛИЗОВАН // #warning Режим записи fwm_fastwrite не реализован static flash_err_t flash_write_comp( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // > Данные страницы прочитываются в буфер 1 чипа ( если запись страницы неполная ) // > Если возможно, производится стирание блока // > Пока блок стирается, модифицируем данные в буфере 1 // > Постранично записываем данные в чип (если требуется, стриание+запись) // --------------------------------- // Вызываем алгоритм быстрой записи fwm_fastwrite flash_err_t success = flash_write_fast( address, pBuffer, size ); // если были ошибки - сообщаем if( FLASH_ERROR( success ) ) return(success); // --------------------------------- // Приступаем к верификации: // > Поочередно загружаем в буфер 1 и буфер 2 страницы для сравнения // > Пока один буфер производит сравнение, записываем данные во второй // > При обнаружении расхождения генерируется ошибка // // ВОПРОС: а будет ли это быстрее, чем сравнивать на ходу?! А может просто прочитать массив на борт CPU и использовать memcmp() ? // // функторы действий // void ( * buffer_write )(__FLASH_WORD,__FLASH_BYTE*,__FLASH_WORD) = __flash_hal__buffer1_write; // сначала выбираем буфер 1 // void ( * buffer_compare )(__FLASH_WORD) = __flash_hal__buffer1_compare; // return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_read - чтение данных по адресу // // * Функция проверяет правильность переданных параметров // * Параметр @address задает линейный адрес внутри адресного пространства устройства. // Адресное пространство с адреса 0 до AT45FLASH_MINIMUM_ADDRESS (не включительно) является // зарезервированным. При попытке чтения из этого диапазона функция вернет ошибку. // Параметр @pvBuffer должен указывать на буфер-приемник для прочитанных данных. // Параметр @size должен указывать на размер буфер-приемника. Параметр показывает // количество байт для чтения в буфер. // # Если параметр @address указывает на адрес в диапазоне 0...AT45FLASH_MINIMUM_ADDRESS, функция вернет ошибку FLERR_INVALID_PARAMETER // # Если параметр @pvBuffer равен NULL, функция вернет ошибку FLERR_INVALID_PARAMETER // # Если параметр @size равен 0, функция вернет ошибку FLERR_INVALID_PARAMETER static flash_err_t flash_api_read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // проверяем входные параметры if( address < AT45FLASH_MINIMUM_ADDRESS ) return(FLERR_INVALID_PARAMETER); if( !pBuffer || !size ) return(FLERR_INVALID_PARAMETER); #ifndef AT45DB161E_EMU512 // проверяем диапазон чтения if( address + size > __FULL_CHIP_SIZE ) return(FLERR_INVALID_PARAMETER); #endif // получаем начальную страницу #ifdef AT45DB161E_EMU512 __FLASH_DWORD PagesToRead = __FLASH_PAGESINRANGE( address , size ); #endif __FLASH_DWORD PageBegin = __FLASH_ADDRESS2PAGE( address ); __FLASH_DWORD PageOffset = __FLASH_ADDRESSOFFSETPAGE( address ); Enter(); // проверям готовность устройства if( FLERR_TIMEOUT == flash_api_getready() ) Return(FLERR_TIMEOUT); #ifndef AT45DB161E_EMU512 // работа без эмуляции страниц по 512 байт AT45_LL_Routines.array_read( PageBegin, PageOffset, pBuffer, size ); Return(FLERR_SUCCESS); #else // эмуляция размера страниц 512 байт // проверяем диапазон чтения if( PagesToRead + PageBegin > __FULL_PAGES ) Return(FLERR_INVALID_PARAMETER); // постраничное чтение while( size && PagesToRead ) { __FLASH_DWORD BytesToRead = __PAGE_SIZE_USER - __FLASH_ADDRESSOFFSETPAGE( address ); if( BytesToRead > size ) BytesToRead = size; // 22/09/15 - ErrorFix AT45_LL_Routines.page_read( PageBegin, PageOffset, pBuffer, BytesToRead ); pBuffer += BytesToRead; address += BytesToRead; size -= BytesToRead; PageBegin++; PagesToRead--; PageOffset = 0; } Return(FLERR_SUCCESS); #endif } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_sleepmode - переход в режим пониженного энергопотребления // # переводит устройство в режим, когда все команды, кроме flash_api_wakeup игнорируются static flash_err_t flash_api_sleepmode() { Enter(); AT45_LL_Routines.sleepmode(); Return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_api_wakeup - выход из режима пониженного энергопотребления // # выводит устройство из режима, когда все команды, кроме flash_api_wakeup игнорируются static flash_err_t flash_api_wakeup() { Enter(); AT45_LL_Routines.wakeup(); if( AT45_LL_Routines.smart_waitms( AT45DBXXX_API_TIMEOUT ) ) { Return(FLERR_SUCCESS); } Return(FLERR_TIMEOUT); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№