// Файл с низкоуровневыми коммандами для W25Q16JV. // v 1.0 от 09/10/20 // Автор: Сычев А. // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№ НИЗКОУРОВНЕВЫЕ НЕБЕЗОПАСНЫЕ ФУНКЦИИ №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ #define W25Q16JV_LOWLEVEL #include "drivers\flash\base\flash_api_types.h" #include "drivers\flash\w25q\common\W25Q_HAL.h" // аппаратная абстрация от SSP #include "drivers\flash\w25q\lowlevel\W25Q16JV_LL.h" // определения для W25Q16JV #include "drivers\flash\w25q\lowlevel\W25Q16JV_LL_func.h" // прототипы LL-функций // ######################################################################################################## static union { __flash_protectionregister_t protSectorFlagsBuffer; struct { __flash_sectorprotectionregister_t sectorFlagsBuffer1; // основной __flash_sectorprotectionregister_t sectorFlagsBuffer2; // копия }; __FLASH_BYTE pageBuffer[ __PAGE_SIZE ]; } flash_hal_Buffer; // __flash_hal__getBuffer - запросить внутренний буфер низкого уровня static void * __flash_hal__getBuffer( __flash_internal_buffer_type_t type, size_t * pRetBufSize ) { void * rValue = NULL; *pRetBufSize = 0; switch( type ) { case fibufSectorFlags: *pRetBufSize = sizeof(flash_hal_Buffer.sectorFlagsBuffer1); rValue = &flash_hal_Buffer.sectorFlagsBuffer1; case fibufSectorFlags_2: *pRetBufSize = sizeof(flash_hal_Buffer.sectorFlagsBuffer2); rValue = &flash_hal_Buffer.sectorFlagsBuffer2; case fibufProtSectorFlags: *pRetBufSize = sizeof(flash_hal_Buffer.protSectorFlagsBuffer); rValue = &flash_hal_Buffer.protSectorFlagsBuffer; case fibufPageIO: *pRetBufSize = sizeof(flash_hal_Buffer.pageBuffer); rValue = &flash_hal_Buffer.pageBuffer[0]; } // обнуление буфера if( NULL != rValue && 0 != *pRetBufSize ) { __imp_sys_memzero( rValue, *pRetBufSize ); } return rValue; } // ######################################################################################################## // __flash_hal__writeDisable - запрещение записи в чип static void __flash_hal__writeDisable(); // __flash_hal__writeEnable - разрешение записи в чип static void __flash_hal__writeEnable(); // __flash_hal__statusRead1 - чтение регистра статуса 1 static void __flash_hal__statusRead1( __flash_status1_t * pcReadRegister ); // буфер для чтения статус-регистра // __flash_hal__statusRead2 - чтение регистра статуса 3 static void __flash_hal__statusRead2( __flash_status2_t * pcReadRegister ); // буфер для чтения статус-регистра // __flash_hal__statusRead3 - чтение регистра статуса 3 static void __flash_hal__statusRead3( __flash_status3_t * pcReadRegister ); // буфер для чтения статус-регистра // __flash_hal__statusWrite1 - запись регистра статуса 1 static void __flash_hal__statusWrite1( __flash_status1_t * pcWriteRegister ); // буфер для записи статус-регистра // __flash_hal__statusWrite2 - запись регистра статуса 3 static void __flash_hal__statusWrite2( __flash_status2_t * pcWriteRegister ); // буфер для записи статус-регистра // __flash_hal__statusWrite3 - запись регистра статуса 3 static void __flash_hal__statusWrite3( __flash_status3_t * pcWriteRegister ); // буфер для записи статус-регистра // __flash_hal__pageErase - стирание страницы static void __flash_hal__pageErase( __FLASH_WORD wPageNum ); // номер стираемой страницы // __flash_hal__blockErase - стирание блока // static void __flash_hal__blockErase( __FLASH_WORD wBlockNum ); // номер стираемого блока // __flash_hal__sectorErase - стирание секторов с номером 1 и выше static void __flash_hal__sectorErase( __FLASH_WORD wSector ); // номер сектора 1-63 // __flash_hal__sleepMode - переход в режим пониженного энергопотребления static void __flash_hal__sleepMode(); // __flash_hal__wakeUp - выход из режима пониженного энергопотребления static void __flash_hal__wakeUp(); // __flash_hal__arrayRead - последовательное чтение (массив) static void __flash_hal__arrayRead ( __FLASH_DWORD w24Address, // адрес начала чтения __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead ); // количество данных на чтение // __flash_hal__chunkProgram - программирование страницы без стирания блока/страницы static void __flash_hal__chunkProgram( __flash_pageprogramptr_t pdata, __FLASH_DWORD w24Address ); // адрес начала записи // __flash_hal__securityRegister1Erase - стирает регистр безопасности static void __flash_hal__securityRegister1Erase(); // __flash_hal__securityRegister2Erase - стирает регистр безопасности static void __flash_hal__securityRegister2Erase(); // __flash_hal__securityRegister3Erase - стирает регистр безопасности static void __flash_hal__securityRegister3Erase(); // __flash_hal__securityRegister1Write - записывает регистр безопасности static void __flash_hal__securityRegister1Write( __flash_securityregister_t * contents ); // содержимое регистра безопасности // __flash_hal__securityRegister2Write - записывает регистр безопасности static void __flash_hal__securityRegister2Write( __flash_securityregister_t * contents ); // содержимое регистра безопасности // __flash_hal__securityRegister3Write - записывает регистр безопасности static void __flash_hal__securityRegister3Write( __flash_securityregister_t * contents ); // содержимое регистра безопасности // __flash_hal__securityRegister1Read - прочитывает регистр безопасности static void __flash_hal__securityRegister1Read( __flash_securityregister_t * contents ); // буфер-приемник содержимого регистра блокировки // __flash_hal__securityRegister2Read - прочитывает регистр безопасности static void __flash_hal__securityRegister2Read( __flash_securityregister_t * contents ); // буфер-приемник содержимого регистра блокировки // __flash_hal__securityRegister3Read - прочитывает регистр безопасности void __flash_hal__securityRegister3Read( __flash_securityregister_t * contents ); // буфер-приемник содержимого регистра блокировки // __flash_hal__manufacturerIdRead - чтение идентификатора производителя static __FLASH_DWORD __flash_hal__manufacturerIdRead( __flash_id_t * pManufacturerID );// необязательный параметр-буфер для приема расширенной информации // __flash_hal__uniqueIdRegisterRead - static void __flash_hal__uniqueIdRegisterRead( __flash_uniqueidregister_t * contents ); // буфер-приемник содержимого регистра UniqueID // __flash_hal__uniqueIdRegisterValidate - прочитывает регистр UniqueID и выполняет static bool __flash_hal__uniqueIdRegisterValidate( __flash_uniqueidregister_t * contents ); // буфер-приемник содержимого регистра UniqueID #if W25QXXX_POWER_MANAGEMENT > 0 // __flash_hal__powerOn - реализует управление питанием микросхемы памяти (подает питание) static void __flash_hal__powerOn(); // __flash_hal__powerOff - реализует управление питанием микросхемы памяти (снимает питание) static void __flash_hal__powerOff(); // __flash_hal__powerPulse - реализует управление питанием микросхемы - формирует импульс перезагрузки static void __flash_hal__powerPulse( __FLASH_WORD nCooldownTime_ms, __FLASH_WORD nStartupTime_ms ); #endif #if W25QXXX_RESET_MANAGEMENT > 0 // __flash_hal__resetAssert - реализует управление сигналом сброса микросхемы памяти (устанавливает сигнал сброса) static void __flash_hal__resetAssert(); // __flash_hal__resetRelease - реализует управление сигналом сброса микросхемы памяти (снимает сигнал сброса) static void __flash_hal__resetRelease(); // __flash_hal__resetPulse - реализует управление сигналом сброса микросхемы памяти (подает законченный импульс сброса) static void __flash_hal__resetPulse(); #endif // __flash_hal__initialize - Низкоуровневая инициализация флешпамяти // # возвращает 0, если все успешно, или код ошибки static flash_err_t __flash_hal__initialize(); // __flash_hal__finalizePrepare - Низкоуровневая функция для подготовки флешпамяти к деинициализации драйвера static flash_err_t __flash_hal__finalizePrepare(); // __flash_hal__dirtyDetect - Низкоуровневое определение наличия чипа (доступности) // Используется во время первичной инициализации в flash_initialize(). static flash_err_t __flash_hal__dirtyDetect(); // __flash_hal__startupDetect - Низкоуровневое определение наличия чипа (доступности) // Используется верхним уровнем API для определения модели установленного чипа памяти static flash_err_t __flash_hal__startupDetect(); // __flash_hal__getReadyFast - проверка занятости без ожидания static flash_err_t __flash_hal__getReadyFast( ); // служебная функция для проверки готовности чипа static int __flash_smartWaitms( __FLASH_WORD wTimems ); // __flash_hal__globalLock - установить блокировку записи на все сектора/блоки static void __flash_hal__globalLock(); // [W25Q OK] // __flash_hal__globalUnlock - снять блокировку записи со всех секторов/блоков static void __flash_hal__globalUnlock(); // [W25Q OK] // __flash_hal__protectStateWrite - записывает индивидуальную блокировку сектора/блока static void __flash_hal__protectStateWrite( size_t nProtSector, bool protectState ); // __flash_hal__protectStateRead - считывает индивидуальную блокировку сектора/блока static bool __flash_hal__protectStateRead( size_t nProtSector ); // __flash_hal__protectregister_write - записывает регистр защиты (биты индивидуальной защиты секторов/блоков) // void __flash_hal__protectregister_write( __flash_protectionregister_t * contents ); // __flash_hal__protectregister_read - прочитывает регистр защиты (биты индивидуальной защиты секторов/блоков) // void __flash_hal__protectregister_read( __flash_protectionregister_t * contents ); // ######################################################################################################## const W25Q_LL_Routines_t W25Q_LL_Routines = { .operations = { .writeDisable = __flash_hal__writeDisable, .writeEnable = __flash_hal__writeEnable, }, .status = { .statusRead1 = __flash_hal__statusRead1, .statusRead2 = __flash_hal__statusRead2, .statusRead3 = __flash_hal__statusRead3, .statusWrite1 = __flash_hal__statusWrite1, .statusWrite2 = __flash_hal__statusWrite2, .statusWrite3 = __flash_hal__statusWrite3, }, .security = { .securityRegister1Erase = __flash_hal__securityRegister1Erase, .securityRegister2Erase = __flash_hal__securityRegister2Erase, .securityRegister3Erase = __flash_hal__securityRegister3Erase, .securityRegister1Write = __flash_hal__securityRegister1Write, .securityRegister2Write = __flash_hal__securityRegister2Write, .securityRegister3Write = __flash_hal__securityRegister3Write, .securityRegister1Read = __flash_hal__securityRegister1Read, .securityRegister2Read = __flash_hal__securityRegister2Read, .securityRegister3Read = __flash_hal__securityRegister3Read, }, .protection = { .globalLock = __flash_hal__globalLock, .globalUnlock = __flash_hal__globalUnlock, .protectStateWrite = __flash_hal__protectStateWrite, .protectStateRead = __flash_hal__protectStateRead, //.readState = __flash_hal__protectregister_read, //.writeState = __flash_hal__protectregister_write, }, .sleep = { .sleepMode = __flash_hal__sleepMode, .wakeUp = __flash_hal__wakeUp, }, .data = { .arrayRead = __flash_hal__arrayRead, .chunkProgram = __flash_hal__chunkProgram, .pageErase = __flash_hal__pageErase, .sectorErase = __flash_hal__sectorErase, }, .id = { .manufacturerIdRead = __flash_hal__manufacturerIdRead, .uniqueIdRegisterRead = __flash_hal__uniqueIdRegisterRead, .uniqueIdRegisterValidate = __flash_hal__uniqueIdRegisterValidate, }, .service = { .startupDetect = __flash_hal__startupDetect, .initialize = __flash_hal__initialize, .finalizePrepare = __flash_hal__finalizePrepare, .dirtyDetect = __flash_hal__dirtyDetect, .getBuf = __flash_hal__getBuffer, }, #if W25QXXX_POWER_MANAGEMENT > 0 .power = { .powerOn = __flash_hal__powerOn, .powerOff = __flash_hal__powerOff, .powerPulse = __flash_hal__powerPulse, }, #endif #if W25QXXX_RESET_MANAGEMENT > 0 .reset = { .resetAssert = __flash_hal__resetAssert, .resetRelease = __flash_hal__resetRelease, .resetPulse = __flash_hal__resetPulse, }, #endif .ready = { .getReadyFast = __flash_hal__getReadyFast, .smartWaitms = __flash_smartWaitms, } }; // ######################################################################################################## // Глобальные переменные #pragma pack( push, 1 ) #ifdef W25QXXX_FLASH_RAM_PLACE _PLACEIN( W25QXXX_FLASH_RAM_PLACE ) #endif static union /* __flash_global */ { __FLASH_BYTE alloc_place[ __FLASH_LL_SVCMEM_SIZE ]; struct /* __flash_var */ { // __FLASH_BYTE pagebuffer[ __FULL_PAGE_SIZE ]; // НЕ ТРЕБУЕТСЯ! буфер под чтение/запись страниц __FLASH_BYTE cmdbuffer [ __FLASH_LL_COMMAND_MAXSIZE ]; // буфер для выполения команд }; }; #pragma pack( pop ) //__flash_protectionregister_t * __flash_internal_getbuffer_protect() { return &protectionregister; } // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // служебные функции управления CS // установка сигнала ChipSelect в активное состояние static inline void chip_sel_active() // [W25Q OK] { __FLASH_HAL_CS_LO(); __FLASH_WAITus(_TIME_CSCLR_us); } // установка сигнала ChipSelect в неактивное состояние static inline void chip_sel_inactive() // [W25Q OK] { __FLASH_WAITus(_TIME_CSSET_us); __FLASH_HAL_CS_HI(); __FLASH_WAITus(_TIME_CSHLD_us); // минимальное время между командами } #if W25QXXX_NO_MS_DELAYS == 1 // №№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№№ // __int_sys_delayms - служебная функция ожидания в мс, если аналог отсутствует у пользователя. // Опция W25QXXX_NO_MS_DELAYS позволяет заменить задержку в мс на задержку в мкс. static inline void __int_sys_delayms( __FLASH_WORD timeout ) // [W25Q OK] { __imp_sys_delayus( timeout * 1000 ); } #endif // -------------------------------------------------------------------------------------------------------- // __flash_smartWaitms - комбинированая функция ожидания заданного количества миллисекунд с // проверкой состояния чипа на предмет того, занят он, или нет. Если не занят, // функция возвращает управление сразу же. Если занят все указанное время, // функция возвратит управление через указанный таймаут (не меньший, но, возможно, больший). // // * не изменяет содержимое внутренних SRAM буферов // * использует системные вызовы для определения количества прошедшего времени // * потоко-небезопасная функция // * производит опрос чипа командой "Запрос статусного регистра" (Status Register Read) // * функция использует вызов функций бесконечного чтения статуса // static void __flash_hal__part_statusread_stage1( __flash_status1_t * pcReadRegister ); static void __flash_hal__part_statusread_stage2( __flash_status1_t * pcReadRegister ); static void __flash_hal__part_statusread_stage3( __flash_status1_t * pcReadRegister ); // // * функция возвращает 1, если достоверно известно, что флаг BUSY сброшен (устройство готово), иначе 0 (требуется повторная проверка) // static int __flash_smartWaitms( __FLASH_WORD wTimems ) // [W25Q OK] { __flash_status1_t r_status; // статус-регистр __flash_hal__part_statusread_stage1( &r_status ); // начинаем считывать // -- -- -- -- -- -- для коротких задержек -- -- -- -- -- -- -- -- -- -- if ( !r_status.bBusy ) // сразу проверяем, если устройство свободно, возвращаем управление { __flash_hal__part_statusread_stage3( 0 ); // завершаем чтение регистра return 1; } if ( wTimems < W25QXXX_SMART_WAIT_THRESHOLD ) // для малых времен ожидания накладно опрашивать чип постоянно { __FLASH_WAITms(wTimems); // выжидаем указанное время __flash_hal__part_statusread_stage3( &r_status ); // проверяем регистр if ( !r_status.bBusy ) // если свободно - вернем 1 return 1; return 0; // если занято - вернем 0 } // -- -- -- -- -- -- для длинных задержек -- -- -- -- -- -- -- -- -- -- __FLASH_DWORD dwStartCounter = __FLASH_SMART_GETTIMER(); // получаем отметку времени for(/*|*/ __FLASH_DWORD dwDeltaCounter = 0; // счетчик задержки /*|*/ dwDeltaCounter < wTimems; // проверяем, задержались ли мы на указанное время или еще нет /*|*/ dwDeltaCounter = ( __FLASH_SMART_GETTIMER() - dwStartCounter ) ) // обновляем счетчик задержки { __flash_hal__part_statusread_stage2( &r_status ); // читаем статус if ( !r_status.bBusy ) // проверяем, не освободился ли чип? { __flash_hal__part_statusread_stage3( 0 ); // да, освободился, завершаем чтение return 1; // возвращаем 1 (освободился) } __FLASH_WAITms(1); // выжидаем квант времени } __flash_hal__part_statusread_stage3( &r_status ); // время вышло, завершаем чтение if ( !r_status.bBusy ) // последний раз проверяем статус return 1; // свободен! return 0; // чип до сих пор занят } // ######################################################################################################## // -------------------------------------------------------------------------------------------------------- // __flash_hal__part_statusread - группа скрытых низкоуровневых функций, позволяющая осуществлять постоянное сканирование регистра // статуса. Чип предоставляет возможность считывать регистр статуса без отправки команды на чтение при повторном чтении, // до установки CS в неактивное положение. Т.О возможно передать команду один раз, затем читать статус бесконечно. // Функции должны вызываться в порядке нумерации, при этом стадия 2 может быть пропущена. Функии проверяют параметр // pcReadRegister на NULL, если он отличен от NULL, считывают в него содержмое регистра, иначе ничего не считывают. // Пример ожидания завершения операции стирания: // [code] // // __flash_status_t status; // статус-регистр // // __flash_hal_pageerase( 0 ); // стираем 0 страницу // __flash_hal__part_statusread_stage1( &status ); // иницируем чтение статуса // // while( status.bBusy ) // __flash_hal__part_statusread_stage2( &status ); // повторяем чтение статуса // // __flash_hal__part_statusread_stage3( 0 ); // завершаем чтение статуса // // [/code] // __flash_hal__part_statusread_stage1 - 1 стадия (начальная) команды бесконечного чтения статуса занятости // __flash_hal__part_statusread_stage2 - 2 стадия (промежуточная) команды бесконечного чтения статуса занятости // __flash_hal__part_statusread_stage3 - 3 стадия (заключительная) команды бесконечного чтения статуса занятости // // * потоко-небезопасная функция // * НЕ задерживает выполнение: требуется внешний цикл для организации сканирования static void __flash_hal__part_statusread_stage1( __flash_status1_t * pcReadRegister ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statusread_t*) cmdbuffer )->opcode = _ACMD_STATREAD_1; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statusread_t) ); if( pcReadRegister ) // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status1_t) ); } //----- ------- ------ ------ ------ ------- ------ static void __flash_hal__part_statusread_stage2( __flash_status1_t * pcReadRegister ) // [W25Q OK] { if( pcReadRegister ) // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status1_t) ); } //----- ------- ------ ------ ------ ------- ------ static void __flash_hal__part_statusread_stage3( __flash_status1_t * pcReadRegister ) // [W25Q OK] { if( pcReadRegister ) // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status1_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__getReadyFast - проверка занятости без ожидания // // # Возвращаемое значение: FLERR_SUCCESS если свободен, иначе FLERR_TIMEOUT static flash_err_t __flash_hal__getReadyFast( ) // [W25Q OK] { __flash_status1_t status; __flash_hal__statusRead1( &status ); if( !status.bBusy ) return FLERR_SUCCESS; return FLERR_TIMEOUT; } /* // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__getprotectstate - получение состояния общего бита защиты // // # Возвращаемое значение - FLERR_PROTECT_ENABLED, если бит защиты установлен, иначе FLERR_PROTECT_DISABLED static flash_err_t __flash_hal__getprotectstate( ) // [W25Q WRONG] { __flash_status1_t status; __flash_hal__statusRead1( &status ); if( status.cBlkProt ) return FLERR_PROTECT_ENABLED; return FLERR_PROTECT_DISABLED; } */ // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__dirtyDetect - Низкоуровневое определение наличия чипа (доступности) // Используется во время первичной инициализации в flash_initialize(). static flash_err_t __flash_hal__dirtyDetect() // [W25Q OK] { // сначала пытаемся прочитать идентификатор: // чтение регистра информации __FLASH_DWORD flashID = __flash_hal__manufacturerIdRead( 0 ); // определяем наличие флешки по идентификатору if( ((__flash_rvid_t*) &flashID)->FullId == __FLASH_INVALID_ID ) { // похоже, что чипа нет, обнаружить не удалось return FLERR_LL_INITFAIL_NOTFOUND; } // еще не все, нужно убедиться, что устройство отвечает: // читаем статус if( ! __flash_smartWaitms( W25QXXX_API_TIMEOUT ) ) { // либо статус не читается, либо устройство занято. // т.к. функция предназначена для использования во время инициализации, // предполагается, что чип должен быть свободен. // Поэтому возвращаем ошибку return FLERR_UNEXPECTED_BUSY; } return FLERR_SUCCESS; } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__finalizePrepare - Низкоуровневая функция для подготовки флешпамяти к деинициализации драйвера // Выполняет действия, направленные на завершение работы с флешпамятью и подготовки ее к выключению // Вызывается в момент окончательной остановки работы с флешпамятью static flash_err_t __flash_hal__finalizePrepare() // [W25Q OK] { // Сначала требуется проверить режим защиты записи: // если разрешено управление аппаратным сигналом защиты записи #if W25QXXX_HW_WR_PROTECT // если аппаратная защита записи отключена в настройках #if W25QXXX_HW_WR_PROTECT_KEEPUNPROTECTED == 1 // требуется установить аппаратную защиту записи после деинициализации драйвера __imp_flash_hwwrprotect_assert(); #endif #endif // Потом проверяем статус готовности if( ! (__flash_smartWaitms( W25QXXX_API_TIMEOUT ) ) ) { // устройство занято. return FLERR_UNEXPECTED_BUSY; } return FLERR_SUCCESS; } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__startupDetect - Низкоуровневое детектирование чипа флешпамяти // Производит начальную настройку аппаратуры для возможности определения наличия чипа на шине static flash_err_t __flash_hal__startupDetect() { // если разрешено управление питанием #if W25QXXX_POWER_MANAGEMENT // подать питание на микросхему __flash_hal__powerOn(); __FLASH_WAITus( _TIME_STRUP_us ); #endif // если разрешено управление питанием #if W25QXXX_RESET_MANAGEMENT // снять сигнлал сброса с чипа __flash_hal__resetRelease(); __FLASH_WAITus( _TIME_RSTRC_us ); #endif // пробуждаем чип, если тот находится в режиме сна // иначе он не будет воспринимать команды. // Неизвестно, был ли чип в режиме гибернации, но это не важно __flash_hal__wakeUp(); // предварительный таймаут запуска - ждем максимальное время до готовности записи во флеш __FLASH_WAITms( _TIME_START_ms ); // производится несколько две попытки достучаться до чипа flash_err_t dirty_status = FLERR_GENERIC_ERROR; for( size_t attempt = 0; attempt < 2; ++attempt ) { // пробуем "грязное" чтение идентификатора. // Результат чтения не сохраняется, требуется обнаружить // лишь присуствие на шине и определить готовность // Поэтому как остуствие на шине, так и занятость чипа расценивается // как ошибка. dirty_status = __flash_hal__dirtyDetect(); if( FLASH_ERROR(dirty_status) ) { // если первая попытка провалена, и __flash_hal__dirtyDetect после сброса // дает ошибку - значит возвращаем ошибку if( attempt > 0 ) return dirty_status; // если разрешено управление сигналом сброса #if W25QXXX_RESET_MANAGEMENT // Формируем импульс сброса: __flash_hal__resetPulse(); #else // управление сигналом сброса недоступно // а управление питанием доступно? #if W25QXXX_POWER_MANAGEMENT // Формируем импульс подачи питания __flash_hal__powerPulse( _TIME_COOLDOWN_ms, _TIME_START_ms ); #else // Проверка доступности вернула ошибку. // Управление питанием и сигналом сброса недоступно // Возвращаем ошибку return dirty_status; #endif #endif } else break; } if( FLASH_ERROR(dirty_status) ) return dirty_status; // чтение регистра информации __FLASH_DWORD flashID = __flash_hal__manufacturerIdRead( 0 ); // определяем наличие флешки по идентификатору if( ((__flash_rvid_t*) &flashID)->FullId == __FLASH_INVALID_ID ) { return FLERR_LL_INITFAIL_NOTFOUND; } __flash_uniqueidregister_t uniqueidRegister; if( !__flash_hal__uniqueIdRegisterValidate( &uniqueidRegister ) ) { return FLERR_LL_INITFAIL_NOTFOUND; } // проверяем ID производителя #ifdef W25QXXX_FLASH_DESIRED_ID if( ((__flash_rvid_t*) &flashID)->LowId != W25QXXX_FLASH_DESIRED_ID ) { return FLERR_LL_INITFAIL_WRONGID; } #endif // проверяем вместимость чипа #ifdef W25QXXX_FLASH_DESIRED_DENSITY if( ((__flash_rvid_t*) &flashID)->DevId.Density != W25QXXX_FLASH_DESIRED_DENSITY ) { return FLERR_LL_INITFAIL_WRONGDENSITY; } #endif // проверяем семейство чипа #if defined(W25QXXX_FLASH_DESIRED_FAMILY_ALT1) || defined(W25QXXX_FLASH_DESIRED_FAMILY_ALT2) switch( ((__flash_rvid_t*) &flashID)->DevId.Family ) { #if defined(W25QXXX_FLASH_DESIRED_FAMILY_ALT1) case W25QXXX_FLASH_DESIRED_FAMILY_ALT1: #endif #if defined(W25QXXX_FLASH_DESIRED_FAMILY_ALT2) case W25QXXX_FLASH_DESIRED_FAMILY_ALT2: #endif break; default: return FLERR_LL_INITFAIL_WRONGFAMILY; } #endif return FLERR_SUCCESS; } // -------------------------------------------------------------------------------------------------------- // ######################################################################################################## // __flash_hal__initialize - Низкоуровневая инициализация драйвера флешпамяти // // * определение наличия подключенной микросхемы // * чтение идентификатора и определение производителя // * контроль правильности: // - идентификатора производителя // - типа устройства, семейства (DevId) // - размера чипа // * установка и проверка размера страницы // // # Возвращаемое значние - код выполнения static flash_err_t __flash_hal__initialize() // [W25Q OK] { // первичная инициализация шины и чипа flash_err_t detectStatus = __flash_hal__startupDetect(); if( FLASH_ERROR(detectStatus) ) return detectStatus; // если разрешено управление аппаратным сигналом защиты записи #if W25QXXX_HW_WR_PROTECT // если аппаратная защита записи отключена в настройках #if W25QXXX_HW_WR_PROTECT_KEEPUNPROTECTED == 1 // требуется снять аппаратную защиту записи на всё время работы драйвера __imp_flash_hwwrprotect_release(); #endif #endif return FLERR_SUCCESS; } // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // ######################################################################################################## // -------------------------------------------------------------------------------------------------------- // __flash_hal__writeEnable - разрешение записи в чип // // * потоко-небезопасная функция // * НЕ задерживает выполнение static void __flash_hal__writeEnable() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_writecontrol_t*) cmdbuffer )->opcode = _SCMD_WRENABLE; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_writecontrol_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__writeDisable - запрещение записи в чип // // * потоко-небезопасная функция // * НЕ задерживает выполнение static void __flash_hal__writeDisable() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_writecontrol_t*) cmdbuffer )->opcode = _SCMD_WRDISABLE; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_writecontrol_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusRead1 - чтение регистра статуса 1 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * НЕ задерживает выполнение static void __flash_hal__statusRead1( __flash_status1_t * pcReadRegister // буфер для чтения статус-регистра ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statusread_t*) cmdbuffer )->opcode = _ACMD_STATREAD_1; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statusread_t) ); // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status1_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusRead2 - чтение регистра статуса 2 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * НЕ задерживает выполнение static void __flash_hal__statusRead2( __flash_status2_t * pcReadRegister // буфер для чтения статус-регистра ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statusread_t*) cmdbuffer )->opcode = _ACMD_STATREAD_2; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statusread_t) ); // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status2_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusRead3 - чтение регистра статуса 3 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * НЕ задерживает выполнение static void __flash_hal__statusRead3( __flash_status3_t * pcReadRegister // буфер для чтения статус-регистра ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statusread_t*) cmdbuffer )->opcode = _ACMD_STATREAD_3; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statusread_t) ); // читаем регистр __FLASH_HAL_RD( pcReadRegister, sizeof(__flash_status3_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusWrite1 - запись регистра статуса 1 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД static void __flash_hal__statusWrite1( __flash_status1_t * pcWriteRegister // буфер для записи статус-регистра ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statuswrite_t*) cmdbuffer )->opcode = _ACMD_STATWRIT_1; ( (__flash_packet_statuswrite_t*) cmdbuffer )->status = pcWriteRegister->status; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statuswrite_t) ); chip_sel_inactive(); #if W25Q16JV_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_STPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusWrite2 - запись регистра статуса 2 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД static void __flash_hal__statusWrite2( __flash_status2_t * pcWriteRegister // буфер для записи статус-регистра ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statuswrite_t*) cmdbuffer )->opcode = _ACMD_STATWRIT_2; ( (__flash_packet_statuswrite_t*) cmdbuffer )->status = pcWriteRegister->status; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statuswrite_t) ); chip_sel_inactive(); #if W25Q16JV_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_STPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // __flash_hal__statusWrite3 - запись регистра статуса 3 // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на ДЕСЯТКИ МИЛЛИСЕКУНД static void __flash_hal__statusWrite3( __flash_status3_t * pcWriteRegister // буфер для записи статус-регистра ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_statuswrite_t*) cmdbuffer )->opcode = _ACMD_STATWRIT_3; ( (__flash_packet_statuswrite_t*) cmdbuffer )->status = pcWriteRegister->status; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_statuswrite_t) ); chip_sel_inactive(); #if W25Q16JV_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_STPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // __flash_hal__arrayRead - последовательное чтение (массив) // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция static void __flash_hal__arrayRead ( __FLASH_DWORD w24Address, // адрес начала чтения __FLASH_BYTE * pDataRead, // указатель на буфер-приемник данных __FLASH_WORD wCntToRead // количество данных на чтение ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_arrayread_t*) cmdbuffer )->opcode = _LCMD_ARRYREAD; __FLASH_LL_FILLADDRESS( ( (__flash_packet_arrayread_t*) cmdbuffer ), w24Address); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_arrayread_t) ); // читаем данные __FLASH_HAL_RD( pDataRead, wCntToRead ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__chunkProgram - программирование страницы без стирания блока/страницы // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на МИЛЛИСЕКУНДЫ static void __flash_hal__chunkProgram( __flash_pageprogramptr_t pdata, __FLASH_DWORD w24Address ) // адрес начала записи { chip_sel_active(); ( (__flash_packet_page_program_t*) cmdbuffer )->opcode = _WCMD_PGWRIT; w24Address &= 0xFFFF00; // сбрасывается адрес внутри страницы 256 байт __FLASH_LL_FILLADDRESS( ( (__flash_packet_page_program_t*) cmdbuffer ), w24Address); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_page_program_t) ); // отправляем данные __FLASH_HAL_WRCMD( pdata, sizeof(*pdata) ); chip_sel_inactive(); #if W25Q16JV_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // __flash_hal__pageErase - стирание страницы // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИЛЛИСЕКУНД static void __flash_hal__pageErase( __FLASH_WORD wPageNum // номер стираемой страницы ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_pageerase_t*) cmdbuffer )->opcode = _ECMD_PAGERASE; __FLASH_LL_FILLADDRESS( ( (__flash_packet_pageerase_t*) cmdbuffer ), ( wPageNum * (__PAGE_SIZE) ) ); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pageerase_t) ); chip_sel_inactive(); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- /* // -------------------------------------------------------------------------------------------------------- // __flash_hal__blockErase - стирание блока (=страницы) // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СОТНИ МИЛЛИСЕКУНД static void __flash_hal__blockErase( __FLASH_WORD wBlockNum // номер стираемого блока ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_blockerase_t*) cmdbuffer )->opcode = _ECMD_PAGERASE; __FLASH_LL_FILLADDRESS( ( (__flash_packet_blockerase_t*) cmdbuffer ), ( wBlockNum * (__PAGE_SIZE) ) ); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_pageerase_t) ); chip_sel_inactive(); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- */ // -------------------------------------------------------------------------------------------------------- // __flash_hal__sectorErase - стирание секторов // // * не проверяет правильность переданных параметров // * потоко-небезопасная функция // * задерживает выполнение на СЕКУНДЫ static void __flash_hal__sectorErase( __FLASH_WORD wSector // номер сектора 0-31 ) // [W25Q OK] { chip_sel_active(); ( (__flash_packet_sectorerase_t*) cmdbuffer )->opcode = _ECMD_SCTERASE; __FLASH_LL_FILLADDRESS( ( (__flash_packet_sectorerase_t*) cmdbuffer ), ( wSector * (__SECTOR_STD_SIZE) ) ); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_sectorerase_t) ); chip_sel_inactive(); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_SCERS_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__sleepMode - переход в режим пониженного энергопотребления // // * потоко-небезопасная функция // # переводит устройство в режим, когда все команды, кроме __flash_hal__wakeUp игнорируются static void __flash_hal__sleepMode() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_powerdown_t*) cmdbuffer )->opcode = _ACMD_EPWRDOWN; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_powerdown_t) ); chip_sel_inactive(); __FLASH_WAITus( _TIME_EDPDM_us ); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__wakeUp - выход из режима пониженного энергопотребления // // * потоко-небезопасная функция // # выводит устройство из режима, когда все команды, кроме __flash_hal__wakeUp игнорируются static void __flash_hal__wakeUp() // [W25Q OK] { chip_sel_active(); // если флеш находилась во сне, необходимо ждать _TIME_RDPDM_us __FLASH_WAITus(_TIME_RDPDM_us); ( (__flash_packet_powerup_t*) cmdbuffer )->opcode = _ACMD_LPWRDOWN; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_powerup_t) ); chip_sel_inactive(); __FLASH_WAITus( _TIME_RDPDM_us ); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__manufacturerIdRead - чтение идентификатора производителя // // * потоко-небезопасная функция // * может использоваться для опеределения типа чипа для выяснения его вместимости // * функция принимает параметр @pManufacturerID типа __flash_id_t. Этот параметр будет содержать // информацию о чипе, если параметр не NULL. Кроме того, для того, чтобы прочитать расширенную // информацию производителя (extended device information), поля pManufacturerID->pExtBf и // pManufacturerID->ExtLen должны быть проининциализированны указателем на принимающий буфер // и длинной этого буфера соответственно. При наличии расширенной информации поле ExtLen будет // перезаписано, и будет содержать длинну расширенной информации, сохраненной по указателю pExtBf. // Память по указателю pExtBf должна быть выделена заранее перед вызовом функции. Нуль-символ не // добавляется. Память, начиная с ExtLen байта, не перезаписывается (остается мусор). // * параметр @pManufacturerID может быть равен NULL. Для того, чтобы НЕ читать расширенную информацию, // передайте NULL вместо pManufacturerID, или, если передаете pManufacturerID, обнулите в нем поля pExtBf и ExtLen. // * функция способна считывать расширенную информацию в формате Serial Flash Discoverable Parameter Structure // (JESD216D.01). Таким образом, кроме стандартного ID производителя длинной 1 байт, производитель записывает // сообщение длинной дл 256 байт [JESD216D.01]. Наличие расширенной информации в выдаваемой структуре // опционально: производитель может не помещать SFDP структуру, либо ее чтение может быть не реализовано. // Для данного формата поле HighId в __flash_id_t не требуется и зарезервировано (всегда равно 0). // * вовзращаемое значение - DWORD, "откушенный" по младшему адресу от структуры __flash_id_t - содержит // DevId, LowId, HighId. static __FLASH_DWORD __flash_hal__manufacturerIdRead( __flash_id_t * pManufacturerID // необязательный параметр-буфер для приема расширенной информации ) // [W25Q OK] { // локальные переменные функции объединены с возвращаемым значением, чтобы вернуть // часть информации в виде DWORD union { struct { __FLASH_BYTE LowId; // стандартный байт ID (не расширенный) __FLASH_BYTE HighId; // расширенный байт ID (количество 0x7F Continuation Code) (JEDEC JEP-106) union { __FLASH_WORD DevId; // код устройства struct { __FLASH_BYTE LDevId; // код устройства (Low) __FLASH_BYTE HDevId; // код устройства (High) }; }; }; __FLASH_DWORD ReturnValue; // возвращаемое значение }; DevId = 0; LDevId = 0; HDevId = 0; LowId = 0; HighId = 0; ReturnValue = 0; //----------- chip_sel_active(); //----------- // чтение JEDEC ID начато ( (__flash_packet_manufactureridread_t*) cmdbuffer )->opcode = _ACMD_MFIDREAD; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_manufactureridread_t) ); // чтение Manufacturer ID __FLASH_HAL_RD( &LowId, sizeof( LowId ) ); // чтение Device ID __FLASH_HAL_RD( &LDevId, sizeof( LDevId ) ); __FLASH_HAL_RD( &HDevId, sizeof( HDevId ) ); // чтение JEDEC ID закончено //----------- chip_sel_inactive(); //----------- // если требуется чтение расширенной информации // @ExtLen > 0 указывает на выделенный буфер под SFDP регистр if( NULL != pManufacturerID && pManufacturerID->ExtLen > 0 ) { chip_sel_active(); //----------- // чтение SFDP начато ( (__flash_packet_sfdp_read_t*) cmdbuffer )->opcode = _ACMD_SFDPREAD; ( (__flash_packet_sfdp_read_t*) cmdbuffer )->zero1 = 0; // A23..A16 must be 0 ( (__flash_packet_sfdp_read_t*) cmdbuffer )->zero1 = 0; // A15..A08 must be 0 ( (__flash_packet_sfdp_read_t*) cmdbuffer )->offset = 0; // чтение по нулевому смещению ( (__flash_packet_sfdp_read_t*) cmdbuffer )->dummy = 0; // фиктивный байт // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_sfdp_read_t) ); // чтение SFDP в буфер for( size_t offset = 0; offset < pManufacturerID->ExtLen; offset++ ) { __FLASH_HAL_RD( pManufacturerID->pExtBf + offset, sizeof( uint8_t ) ); } //----------- chip_sel_inactive(); } //----------- return ReturnValue; } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__globalUnlock - снять блокировку записи со всех секторов/блоков / выключить программную защиту от записи/стирания // // * потоко-небезопасная функция static void __flash_hal__globalUnlock() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_globallockcontrol_t*) cmdbuffer )->opcode = _SCMD_GLBLUNLK; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_globallockcontrol_t) ); chip_sel_inactive(); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__globalLock - установить блокировку записи на все сектора/блоки / включить программную защиту от записи/стирания // // * потоко-небезопасная функция static void __flash_hal__globalLock() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_globallockcontrol_t*) cmdbuffer )->opcode = _SCMD_GLBLLK; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_globallockcontrol_t) ); chip_sel_inactive(); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__protectStateWrite - записывает индивидуальную блокировку сектора/блока // // * потоко-небезопасная функция // * не проверяет правильность переданных параметров // * задерживает выполнение на МИЛЛИСЕКУНДЫ static void __flash_hal__protectStateWrite( size_t nProtSector, bool protectState ) // [W25Q OK] { chip_sel_active(); if( protectState ) ( (__flash_packet_protectregister_rw_t*) cmdbuffer )->opcode = _SCMD_BLKLOCK; else ( (__flash_packet_protectregister_rw_t*) cmdbuffer )->opcode = _SCMD_BLKULOCK; __FLASH_LL_FILLADDRESS( ( (__flash_packet_protectregister_rw_t*) cmdbuffer ), __PROT_SECTOR_TO_ADDRESS(nProtSector) ); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protectregister_rw_t) ); chip_sel_inactive(); #if W25QXXX_BKGOPERATIONS == 0 //! __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__protectStateRead - считывает индивидуальную блокировку сектора/блока // // * потоко-небезопасная функция // * не проверяет правильность переданных параметров static bool __flash_hal__protectStateRead( size_t nProtSector ) // [W25Q OK] { chip_sel_active(); uint8_t state = 0; ( (__flash_packet_protectregister_rw_t*) cmdbuffer )->opcode = _SCMD_BLKLKRD; __FLASH_LL_FILLADDRESS( ( (__flash_packet_protectregister_rw_t*) cmdbuffer ), __PROT_SECTOR_TO_ADDRESS(nProtSector) ); // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_protectregister_rw_t) ); // считывается бит защиты __FLASH_HAL_RD( &state, sizeof( uint8_t ) ); chip_sel_inactive(); // LSB бит показывает состояние защиты, 0-нет защиты, 1-защита включена return ((bool)(state & 1)); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister1Write - записывает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * ИЗМЕНЯЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО РЕГИСТРА БЕЗОПАСНОСТИ 1 static void __flash_hal__securityRegister1Write( __flash_securityregister_t * contents // содержимое регистра безопасности ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->opcode = _SCMD_SECRGWRT; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->regSelector = 1; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->byteSelector = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); // записываем регистр безопасности __FLASH_HAL_WR( contents, sizeof(__flash_securityregister_t) ); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister2Write - записывает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * ИЗМЕНЯЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО РЕГИСТРА БЕЗОПАСНОСТИ 2 static void __flash_hal__securityRegister2Write( __flash_securityregister_t * contents // содержимое регистра безопасности ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->opcode = _SCMD_SECRGWRT; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->regSelector = 2; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->byteSelector = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); // записываем регистр безопасности __FLASH_HAL_WR( contents, sizeof(__flash_securityregister_t) ); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister3Write - записывает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * ИЗМЕНЯЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО РЕГИСТРА БЕЗОПАСНОСТИ 3 static void __flash_hal__securityRegister3Write( __flash_securityregister_t * contents // содержимое регистра безопасности ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->opcode = _SCMD_SECRGWRT; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->regSelector = 3; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregisterwrite_t*) cmdbuffer )->byteSelector = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); // записываем регистр безопасности __FLASH_HAL_WR( contents, sizeof(__flash_securityregister_t) ); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGPRG_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister1Erase - стирает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * СТИРАЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО РЕГИСТРА БЕЗОПАСНОСТИ 1 static void __flash_hal__securityRegister1Erase() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_securityregistererase_t*) cmdbuffer )->opcode = _SCMD_SECRGERS; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->regSelector = 1; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero_3 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister2Erase - стирает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * СТИРАЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО РЕГИСТРА БЕЗОПАСНОСТИ 2 static void __flash_hal__securityRegister2Erase() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_securityregistererase_t*) cmdbuffer )->opcode = _SCMD_SECRGERS; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->regSelector = 2; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero_3 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister3Erase - стирает регистр безопасности // // * потоко-небезопасная функция // * параметр @contents не может быть равен NULL // * СТИРАЕТ СОДЕРЖИМОЕ ВСТРОЕННОГО РЕГИСТРА БЕЗОПАСНОСТИ 3 static void __flash_hal__securityRegister3Erase() // [W25Q OK] { chip_sel_active(); ( (__flash_packet_securityregistererase_t*) cmdbuffer )->opcode = _SCMD_SECRGERS; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->regSelector = 3; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregistererase_t*) cmdbuffer )->zero_3 = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterwrite_t) ); #if W25QXXX_BKGOPERATIONS == 0 __FLASH_SMART_WAITms( _TIME_PGERS_ms ); #endif chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister1Read - прочитывает регистр безопасности #1 // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер-приемние для сохранения содержимого регистра блокировки (см. __flash_securityregister_t) // * считывает как пользовательскую часть, так и запрограммированную производителем static void __flash_hal__securityRegister1Read( __flash_securityregister_t * contents // буфер-приемник содержимого регистра блокировки ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterread_t*) cmdbuffer )->opcode = _SCMD_SECRGRD; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->regSelector = 1; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->byteSelector = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterread_t) ); // читаем регистр безопасности __FLASH_HAL_RD( contents, sizeof(__flash_securityregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister2Read - прочитывает регистр безопасности #1 // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер-приемние для сохранения содержимого регистра блокировки (см. __flash_securityregister_t) // * считывает как пользовательскую часть, так и запрограммированную производителем static void __flash_hal__securityRegister2Read( __flash_securityregister_t * contents // буфер-приемник содержимого регистра блокировки ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterread_t*) cmdbuffer )->opcode = _SCMD_SECRGRD; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->regSelector = 2; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->byteSelector = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterread_t) ); // читаем регистр безопасности __FLASH_HAL_RD( contents, sizeof(__flash_securityregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__securityRegister3Read - прочитывает регистр безопасности #3 // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер-приемние для сохранения содержимого регистра блокировки (см. __flash_securityregister_t) // * считывает как пользовательскую часть, так и запрограммированную производителем static void __flash_hal__securityRegister3Read( __flash_securityregister_t * contents // буфер-приемник содержимого регистра блокировки ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_securityregisterread_t*) cmdbuffer )->opcode = _SCMD_SECRGRD; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->zero = 0; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->regSelector = 3; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->zero_2 = 0; ( (__flash_packet_securityregisterread_t*) cmdbuffer )->byteSelector = 0; // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_securityregisterread_t) ); // читаем регистр безопасности __FLASH_HAL_RD( contents, sizeof(__flash_securityregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__uniqueIdRegisterRead - прочитывает регистр уникального идентификатора (UniqueID) // // * потоко-небезопасная функция // * параметр @contents не может быть NULL - укажите буфер-приемнике для сохранения содержимого регистра UniqueID (см. __flash_uniqueidregister_t) static void __flash_hal__uniqueIdRegisterRead( __flash_uniqueidregister_t * contents // буфер-приемник содержимого регистра UniqueID ) // [W25Q OK] { if( !contents ) return; chip_sel_active(); ( (__flash_packet_uid_read_t*) cmdbuffer )->opcode = _ACMD_UIDRREAD; ( (__flash_packet_uid_read_t*) cmdbuffer )->zero1 = 0; // передается фиктивный байт ( (__flash_packet_uid_read_t*) cmdbuffer )->zero2 = 0; // передается фиктивный байт ( (__flash_packet_uid_read_t*) cmdbuffer )->zero3 = 0; // передается фиктивный байт ( (__flash_packet_uid_read_t*) cmdbuffer )->zero4 = 0; // передается фиктивный байт // отправляем команду __FLASH_HAL_WRCMD( &cmdbuffer, sizeof(__flash_packet_uid_read_t) ); // читаем регистр UniqueID __FLASH_HAL_RD( contents, sizeof(__flash_uniqueidregister_t) ); chip_sel_inactive(); } // -------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------- // __flash_hal__uniqueIdRegisterValidate - прочитывает регистр UniqueID и выполняет // проверку осмысленности прочитанного заводского идентификатора. // Функция расценивает индентификатор состоящий из одних 0xFF или 0x00 как невозможный. // В этом случае имеет место ошибка, функция возвращает false. static bool __flash_hal__uniqueIdRegisterValidate( __flash_uniqueidregister_t * contents // буфер-приемник содержимого регистра UniqueID ) // [W25Q OK] { if( NULL != contents ) { __flash_hal__uniqueIdRegisterRead( contents ); __FLASH_DWORD n00 = 0; __FLASH_DWORD nFF = 0; for( __FLASH_DWORD i = 0; i < sizeof(contents->uid); ++i ) { if( 0xFF == contents->uid[i] ) ++nFF; if( 0x00 == contents->uid[i] ) ++n00; } if( (n00 != sizeof(contents->uid)) && (nFF != sizeof(contents->uid)) ) { return true; } } return false; } // -------------------------------------------------------------------------------------------------------- #if W25QXXX_POWER_MANAGEMENT > 0 // -------------------------------------------------------------------------------------------------------- // __flash_hal__powerOn - реализует управление питанием микросхемы памяти (подает питание) // static void __flash_hal__powerOn() // [W25Q OK] { // снять сигнал выбора чипа (чип не выбран, режим idle) chip_sel_inactive(); // подать питание __imp_flash_poweron(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__powerOff - реализует управление питанием микросхемы памяти (снимает питание) // static void __flash_hal__powerOff() // [W25Q OK] { // снять питание __imp_flash_poweroff(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__powerPulse - реализует управление питанием микросхемы - формирует импульс перезагрузки static void __flash_hal__powerPulse( __FLASH_WORD nCooldownTime_ms, __FLASH_WORD nStartupTime_ms ) // [W25Q OK] { // снять питание __imp_flash_poweroff(); // снять сигнал выбора чипа (чип не выбран, режим idle) chip_sel_inactive(); if( nCooldownTime_ms > 0 ) { // немного подождем, пока остынет :) __FLASH_WAITms( _TIME_COOLDOWN_ms ); } else { // ждем совсем немного __FLASH_WAITus( _TIME_STRUP_us ); } // подать питание __imp_flash_poweron(); // если разрешено управление режимом сброса #if W25QXXX_RESET_MANAGEMENT // сформировать импульс сброса микросхемы __flash_hal__resetPulse(); #endif if( nStartupTime_ms > 0 ) { // ожидать готовности __FLASH_WAITms( _TIME_START_ms ); } else { // ждем совсем немного __FLASH_WAITus( _TIME_STRUP_us ); } } #endif #if W25QXXX_RESET_MANAGEMENT > 0 // -------------------------------------------------------------------------------------------------------- // __flash_hal__resetAssert - реализует управление сигналом сброса микросхемы памяти (устанавливает сигнал сброса) // static void __flash_hal__resetAssert() // [W25Q OK] { // снять сигнал выбора чипа (чип не выбран, режим idle) chip_sel_inactive(); // установить сигнал сброса __imp_flash_reset_assert(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__resetRelease - реализует управление сигналом сброса микросхемы памяти (снимает сигнал сброса) // static void __flash_hal__resetRelease() // [W25Q OK] { // снять сигнал сброса __imp_flash_reset_release(); } // -------------------------------------------------------------------------------------------------------- // __flash_hal__resetPulse - реализует управление сигналом сброса микросхемы памяти (подает законченный импульс сброса) // static void __flash_hal__resetPulse() // [W25Q OK] { // формируем импульс сброса // сначала снимаем сигнал сброса __imp_flash_reset_release(); // после снятия сигнала сброса необходимо ожидать время восстановления __FLASH_WAITus(_TIME_RSTRC_us); // потом ставим сигнал сброса __flash_hal__resetAssert(); // ожидание: требуется время для реакции на сигнал сброса __FLASH_WAITus(_TIME_RSTWD_us); // потом снова снимаем __flash_hal__resetRelease(); // после снятия сигнала сброса необходимо ожидать время восстановления __FLASH_WAITus(_TIME_RSTRC_us); } #endif