// Файл с API функциями работы с FLASH-чипом AT45DB321D // v 1.6 от 16/04/19 // Автор: Сычев А. #define AT45DB321D_API_C #define AT45DB321D_APILEVEL // использование интерфейса низкоуровневых функций #include "drivers\flash\lowlevel\AT45DB321D_GLOB.h" #include "drivers\flash\lowlevel\AT45DB321D_LL_func.h" #include "drivers\flash\api\AT45DB321D_API.h" #include "drivers\flash\common\AT45DBXXX_HAL.h" #include "drivers\flash\api\AT45DB321D_APIfunc.h" const flash_properties_t FlashProperties = { .minAddress = AT45FLASH_MINIMUM_ADDRESS, .maxAddress = AT45FLASH_MAXIMUM_ADDRESS, .maxSectors = AT45FLASH_SECTORS, .sectorSize = (AT45FLASH_PAGES_PER_SECTOR * AT45FLASH_PAGE_SIZE), }; // 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_initialize(...) // Высокоуровневая инициализация памяти (установка размера страницы, установка параметров защиты секторов...) // flash_erase(...) // стирание памяти (блоками, страницами или секторами) // flash_read(...) // чтение памяти по адресу // flash_protect(...) // защита секторов (модификация конфигурации защищаемых секторов) // flash_unprotect(...) // снятие защиты (модификация конфигурации защищаемых секторов) // flash_service(...) // получение информации о производителе, расширенной информации, размере памяти, размере страницы, количестве секторов, блоков, страниц и т.п. // flash_write(...) // запись памяти по адресу // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_getready - проверка готовности устройства (со стандартным таймаутом) // // # Функция возвращает FLERR_SUCCESS, еслиу устройство готово, иначе FLERR_TIMEOUT static flash_err_t flash_getready() { Enter(); if( __flash_smart_waitms( _TIME_FLASHAPI_TIMEOUT ) ) { Return(FLERR_SUCCESS); } Return(FLERR_TIMEOUT); } static flash_err_t flash_getready_time( __FLASH_WORD timeout ) { Enter(); if( __flash_smart_waitms( timeout ) ) { Return(FLERR_SUCCESS); } Return(FLERR_TIMEOUT); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_initialize - инициализация драйвера и API работы с устройством // // # Функция возвращает FLERR_SUCCESS. Только в этом случае гарантируется нормальная работа. // # Функция возвращает ошибку инициализации при появлении сбоев или при непрохождении проверки (см файл конфигурации AT45DB321D_CONF.h) flash_err_t flash_initialize() { // производим нисзкоуровневую инициализацию: подаем питание и будим, проверяем наличие чипа, серию, производителя, размер... flash_err_t success = __flash_hal__initialize(); if( FLASH_ERROR(success) ) { // что-то пошло не так: ай печаль-печаль. return(success); } // отключаем защиту секторов при инициализации (общий бит защиты) success = flash_unprotect( 0 ); if( FLASH_ERROR(success) ) { // что-то пошло не так: ай печаль-печаль. return(success); } // считываем статус if( ! __flash_smart_waitms( _TIME_FLASHAPI_TIMEOUT ) ) { // что-то пошло не так: ай печаль-печаль. return(success); } return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_finalize - безопасная де-инициализация драйвера // Функция завершает работу с флеш-памятью, отключаяя ее или переводя в режим гибернации // @bHibernate: булевый флаг, показывает, что нужно перевести флеш-память в режим гибернации, // если false - драйвер попытается отключить питание микросхемы, если разрешено управление питанием (AT45DB321D_POWER_MANAGEMENT) // если false и управление питанием запрещено, будет возвращена ошибка FLERR_INVALID_PARAMETER. // @bForce: насильное выполнение финализации в случае, если флеш-память занята незаконченной операцией. // если false и драйвер детектирует незаконченную операцию, будет возвращена ошибка FLERR_UNEXPECTED_BUSY. // Если выбран режим гибернации, после выдачи команды функция проверяет, уснула ли микросхема через чтение статуса. // Если в этом случае обнаруживается, что статус все еще считывается, генерируется ошибка FLERR_GENERIC_ERROR. // Данную проверку можно отключить опцией AT45DB321D_DONOTCHECK_HIBERNATE=1. // Внимание: проверка не реализуется если bHibernate=false. // # Функция возвращает FLERR_SUCCESS всегда, за исключением вышеописанных случаев. flash_err_t flash_finalize( bool bHibernate, bool bForce ) { Enter(); // подготовка к деинициализации flash_err_t status = __flash_hal__finalize_prepare(); if( FLASH_ERROR(status) ) { // ошибка, обнаружена проблема - устройство не готово // проверяем, разрешено ли принудительное завершение? if( bForce ) { // разрешено, сначала производим сброс // доступно управление сигналом сброса? #if AT45DB321D_RESET_MANAGEMENT // да, производим сброс чипа __flash_hal__reset_pulse(); #else // нет, а доступно управление питанием? #if AT45DB321D_POWER_MANAGEMENT // да, производим быстрый сброс чипа по питанию __flash_hal__power_pulse( 0, 0 ); #else // нет, управление питанием тоже недоступно // возвращаем ошибку FLERR_INVALID_PARAMETER - невозможно выполнить принудительное отключение Return(FLERR_INVALID_PARAMETER); #endif #endif } else { // нет, принудительное завершение запрещено // возвращаем ошибку Return(status); } } // все нормально, продолжаем // выбран режим гибернации? if( bHibernate ) { // отправляем микросхему поспать __flash_hal__sleepmode(); #if AT45DB321D_DONOTCHECK_HIBERNATE == 0 // проверяем, ответит ли микросхема? if( __flash_smart_waitms( _TIME_FLASHAPI_TIMEOUT ) ) { // отвечает - бит готовности прочитался... // Может это просто подтянутый сигнал к +VCC? // попробуем по другому: if( FLASH_SUCCESS(__flash_hal__detect()) ) { // ответила! значит точно не ложилась спать - ошибка Return(FLERR_GENERIC_ERROR); } } #endif } else { // доступно управление питанием? #if AT45DB321D_POWER_MANAGEMENT == 0 // нет, недоступно, нечего делать, генерируем ошибку Return(FLERR_INVALID_PARAMETER); #else // Доступно, отключаем питание. __flash_hal__power_off(); // не проверяем доступность, доверяем функции отключения питания #endif } Return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_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 при отсутствии ошибок // flash_err_t flash_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 = __flash_hal__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; // получение ДЛИННЫ расширенной информации __flash_hal__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; // получение расширенной информации __flash_hal__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( __flash_hal__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_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_protect_ex - установить/снять защиту секторов // Поробности см. описание flash_protect() / flash_unprotect() // // @mode: flash_sector_unprotected - вызов из flash_unprotect() // @mode: flash_sector_protected - вызов из flash_protect() // flash_err_t flash_protect_ex( flash_api_protect_t * content, flash_api_protect_bits mode ) { Enter(); // проверяем устройство на занятость if( FLERR_TIMEOUT == flash_getready() ) Return(FLERR_TIMEOUT); // проверяем на NULL переданный параметр if( !content ) { if( mode == flash_sector_unprotected ) { // параметр NULL - значит СНИМАЕМ общий бит защиты __flash_hal__writeprotect_disable(); // проверяем, сборсился ли бит защиты if( __flash_hal__getprotectstate() != FLERR_PROTECT_DISABLED ) Return(FLERR_GENERIC_ERROR); } else { // параметр NULL - значит УСТАНАВЛИВАЕМ общий бит защиты __flash_hal__writeprotect_enable(); // проверяем, установился ли бит защиты if( __flash_hal__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 ) { // устанавливаем защиту __flash_hal__writeprotect_enable(); if( __flash_hal__getprotectstate() != FLERR_PROTECT_ENABLED ) Return(FLERR_GENERIC_ERROR); } // flash_sector_unprotected else { // снимаем защиту __flash_hal__writeprotect_disable(); if( __flash_hal__getprotectstate() != FLERR_PROTECT_DISABLED ) Return(FLERR_GENERIC_ERROR); } break; default: // неправильный параметр в поле protection_modify Return(FLERR_INVALID_PARAMETER); } // получаем указатель на буфер драйвера __flash_protectionregister_t * pReg = __flash_internal_getbuffer_protect(); // зануляем память __FLASH_ZEROMEMORY( pReg, sizeof(__flash_protectionregister_t) ); // считываем байты защиты __flash_hal__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 { /* не модифицировать статус защиты сектора */ } } //------------------------------------------------------ // // стираем регистр защиты __flash_hal__protectregister_erase(); // проверяем готовность устройства #if AT45DB321D_BKGOPERATIONS if( FLERR_TIMEOUT == flash_getready_time( _TIME_PGERS_ms ) ) #else if( FLERR_TIMEOUT == flash_getready() ) #endif { // фатальная ошибка: регистр защиты стерт // устройство занято. продолжать не можем // // для восстановления регистра защиты необходимо // вызвать функцию flash_error_restore() // Return(FLERR_UNEXPECTED_BUSY); } // записываем регистр защиты __flash_hal__protectregister_write( pReg ); //------------------------------------------------------ // // проверяем готовность устройства #if AT45DB321D_BKGOPERATIONS if( FLERR_TIMEOUT == flash_getready_time( _TIME_PGPRG_ms ) ) #else if( FLERR_TIMEOUT == flash_getready() ) #endif { // Ошибка: запись длится дольше положенного времени Return(FLERR_TIMEOUT); } //------------------------------------------------------ { // №№№№№№ ПРОВЕРКА №№№№№№ // считываем байты защиты __flash_hal__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_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 в случае, если хотя бы один из выбранных битов защиты не был установлен/сброшен // flash_err_t flash_protect( flash_api_protect_t * content ) { return( flash_protect_ex( content, flash_sector_protected )); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_protect - снять защиту секторов. Функция аналогичная flash_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 в случае, если хотя бы один из выбранных битов защиты не был установлен/сброшен // flash_err_t flash_unprotect( flash_api_protect_t * content ) { return( flash_protect_ex( content, flash_sector_unprotected )); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_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 (снята). flash_err_t flash_getprotect( flash_api_getprotect_t * content ) { Enter(); __flash_status_t status; // пользователь хочет получить детализацию по защите секторов if( content ) { if( FLERR_TIMEOUT == flash_getready() ) Return(FLERR_TIMEOUT); // получаем указатель на буфер драйвера __flash_protectionregister_t * pReg = __flash_internal_getbuffer_protect(); // зануляем память __FLASH_ZEROMEMORY( pReg, sizeof(__flash_protectionregister_t) ); // считываем байты защиты __flash_hal__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) ); } } __flash_hal__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_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 если во время операции устройство перестало отвечать // flash_err_t flash_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 ) ) // проверяем количество страниц { // можно! // стираем блок - это быстрее __flash_hal__block_erase( __FLASH_PAGE2BLOCK( PageBegin ) ); #if AT45DB321D_BKGOPERATIONS if( FLERR_TIMEOUT == flash_getready_time( _TIME_BKERS_ms ) ) #else if( FLERR_TIMEOUT == flash_getready() ) #endif { // фатальная ошибка: устройство занято дольше обычного Return(FLERR_UNEXPECTED_BUSY); } PageBegin += __PAGES_PER_BLOCK; PagesToErase -= __PAGES_PER_BLOCK; } else { // нельзя __flash_hal__page_erase( PageBegin ); #if AT45DB321D_BKGOPERATIONS if( FLERR_TIMEOUT == flash_getready_time( _TIME_PGERS_ms ) ) #else if( FLERR_TIMEOUT == flash_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 ) { __flash_hal__block_erase( start ); #if AT45DB321D_BKGOPERATIONS if( FLERR_TIMEOUT == flash_getready_time( _TIME_BKERS_ms ) ) #else if( FLERR_TIMEOUT == flash_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 ) { __flash_hal__sector_erase( start ); #if AT45DB321D_BKGOPERATIONS if( FLERR_TIMEOUT == flash_getready_time( _TIME_SCERS_ms ) ) #else if( FLERR_TIMEOUT == flash_getready() ) #endif { // фатальная ошибка: устройство занято дольше обычного Return(FLERR_UNEXPECTED_BUSY); } start ++; count --; } } break; default: Return(FLERR_INVALID_PARAMETER); } // успех. Return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_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 имеет значение, отличное от перечисленных // // # Для быстрой работы требует включения режима AT45DB321D_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 ); flash_err_t flash_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 // # НЕ ПРОВЕРЯЕТ ПЕРЕДАННЫЕ ПАРАМЕТРЫ // # Для быстрой работы требует включения режима AT45DB321D_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 чипа __flash_hal__pagetobuffer1( pageBegin ); #if AT45DB321D_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif if( FLASH_ERROR( __flash_hal__getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); // Данные страницы прочитываются в буфер 2 чипа __flash_hal__pagetobuffer2( pageBegin ); #if AT45DB321D_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif if( FLASH_ERROR( __flash_hal__getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); } //--------------------- if( size < BytesToWrite ) BytesToWrite = size; //--------------------- // Производится модификация данных в буфере 1 (запись в буфер со смещением) __flash_hal__buffer1_write( __FLASH_ADDRESSOFFSETPAGE( address ), // смещение в буфере pBuffer, // данные BytesToWrite ); // количество данных на запись //--------------------- // идет запись: СТИРАНИЕ + ПРОГРАММИРОВАНИЕ __flash_hal__buffer1_program( pageBegin ); #if AT45DB321D_BKGOPERATIONS == 0 if( FLASH_ERROR( __flash_hal__getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // Производится модификация данных в буфере 2 (запись в буфер со смещением) __flash_hal__buffer2_write( __FLASH_ADDRESSOFFSETPAGE( address ), // смещение в буфере pBuffer, // данные BytesToWrite ); // количество данных на запись //--------------------- // дожидаемся завершения записи #if AT45DB321D_BKGOPERATIONS if( FLASH_ERROR( flash_getready_time( _TIME_PGEPR_ms ) ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // Производится сравнение записанной страницы с буфером 2 __flash_hal__buffer1_compare( pageBegin ); #if AT45DB321D_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif //--------------------- // Если данные совпадают - запись без ошибок if( FLASH_ERROR( __flash_hal__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 // # НЕ ПРОВЕРЯЕТ ПЕРЕДАННЫЕ ПАРАМЕТРЫ // # Для быстрой работы требует включения режима AT45DB321D_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 чипа __flash_hal__pagetobuffer1( pageBegin ); #if AT45DB321D_BKGOPERATIONS __FLASH_WAITus( _TIME_BLDCM_us ); #endif if( FLASH_ERROR( __flash_hal__getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); } //--------------------- if( size < BytesToWrite ) BytesToWrite = size; //--------------------- // Производится стирание блока if( __FLASH_PAGE_ARRAGED_BY_BLOCK( pageBegin ) && PagesToWrite >= AT45FLASH_PAGES_PER_BLOCK ) { __flash_hal__block_erase( __FLASH_PAGE2BLOCK( pageBegin ) ); PagesErased = AT45FLASH_PAGES_PER_BLOCK; // запоминаем, что много-много страниц стерто } //--------------------- // Производится модификация данных в буфере 1 (запись в буфер со смещением) __flash_hal__buffer1_write( __FLASH_ADDRESSOFFSETPAGE( address ), // смещение в буфере pBuffer, // данные BytesToWrite ); // количество данных на запись #if AT45DB321D_BKGOPERATIONS //--------------------- // дожидаемся окончания стирания блока if( AT45FLASH_PAGES_PER_BLOCK == PagesErased ) // Только если только что стерли. if( FLASH_ERROR( flash_getready_time( _TIME_BKERS_ms ) ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // если стерто много страниц (блочное стирание ) if( PagesErased ) // идет запись: ПРОГРАММИРОВАНИЕ БЕЗ СТИРАНИЯ { __flash_hal__buffer1_program_wo_erase( pageBegin ); PagesErased--; } else // идет запись: СТИРАНИЕ + ПРОГРАММИРОВАНИЕ __flash_hal__buffer1_program( pageBegin ); #if AT45DB321D_BKGOPERATIONS == 0 if( FLASH_ERROR( __flash_hal__getreadyfast() ) ) Return(FLERR_UNEXPECTED_BUSY); #endif //--------------------- // дожидаемся завершения записи #if AT45DB321D_BKGOPERATIONS if( FLASH_ERROR( flash_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 // # НЕ ПРОВЕРЯЕТ ПЕРЕДАННЫЕ ПАРАМЕТРЫ // # Для быстрой работы требует включения режима AT45DB321D_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_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 flash_err_t flash_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 AT45DB321D_EMU512 // проверяем диапазон чтения if( address + size > __FULL_CHIP_SIZE ) return(FLERR_INVALID_PARAMETER); #endif // получаем начальную страницу #ifdef AT45DB321D_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_getready() ) Return(FLERR_TIMEOUT); #ifndef AT45DB321D_EMU512 // работа без эмуляции страниц по 512 байт __flash_hal__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 __flash_hal__page_read( PageBegin, PageOffset, pBuffer, BytesToRead ); pBuffer += BytesToRead; address += BytesToRead; size -= BytesToRead; PageBegin++; PagesToRead--; PageOffset = 0; } Return(FLERR_SUCCESS); #endif } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_sleepmode - переход в режим пониженного энергопотребления // # переводит устройство в режим, когда все команды, кроме flash_wakeup игнорируются flash_err_t flash_sleepmode() { Enter(); __flash_hal__sleepmode(); Return(FLERR_SUCCESS); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // flash_wakeup - выход из режима пониженного энергопотребления // # выводит устройство из режима, когда все команды, кроме flash_wakeup игнорируются flash_err_t flash_wakeup() { Enter(); __flash_hal__wakeup(); if( __flash_smart_waitms( _TIME_FLASHAPI_TIMEOUT ) ) { Return(FLERR_SUCCESS); } Return(FLERR_TIMEOUT); } // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№