#define EXTMEM_FLASH_C #include "core/config.h" #include "drivers/flash/base/extmem_flash.h" #include "core/gpio.h" #include "core/main.h" #include "core/config_pins.h" #define pSPIHandle (&SPIHandle) #if AT45DBXXX_POWER_MANAGEMENT || W25QXXX_POWER_MANAGEMENT static void ExtMem_SetPinPowerOn(); static void ExtMem_SetPinPowerOff(); #endif #if AT45DBXXX_RESET_MANAGEMENT || W25QXXX_RESET_MANAGEMENT static void ExtMem_ResetPinAssert(); static void ExtMem_ResetPinRelease(); #endif #if AT45DBXXX_HW_WR_PROTECT || W25QXXX_HW_WR_PROTECT static void ExtMem_HwWrProtPinAssert(); static void ExtMem_HwWrProtPinRelease(); #endif static bool ExtMem_Write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ); static bool ExtMem_Read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ); static bool ExtMem_RangeCheck_Read( flash_address_t address, flash_address_t size ); static bool ExtMem_RangeCheck_Write( flash_address_t address, flash_address_t size ); static bool ExtMem_BankProtect( eExtMem_Bank_t bankId, bool protectStatus ); static bool ExtMem_CheckBankProtect( eExtMem_Bank_t bankId, bool * pActualProtectStatus ); static void ExtMem_Pins_Init(); static void ExtMem_Pins_Deinit(); static bool ExtMem_DeInit( bool bForce ); static bool ExtMem_Init(); // ----------------------------------------------------------------------------- // Memory Banking Template // Divides the whole chip memory into the common banks // This structure describes the sectors mask included into the bank typedef struct { struct flash_sectors_st selectRegister; } sMemoryBankingTemplate_t; static void ExtMem_Internal_FillBankingTemplate( const ExtMem_Bank_Properties_t * pBankProperties, sMemoryBankingTemplate_t * pFactoryProtectionTemplate ); // ----------------------------------------------------------------------------- volatile bool bExtMemStatus = false; typedef struct { const flash_api_descriptor_t * api; } ExtMemDriver_t; // Supported flash-drivers static const ExtMemDriver_t flash_drivers[] = { { &W25Q16JV_API } // W25Q driver }; static const ExtMemDriver_t * flashDriver = NULL; // active driver pointer #define EXTMEM_BANK0_SIZE (0x0E0000) #define EXTMEM_BANK1_SIZE (0x100000) // Dynamically filled Bank properties static ExtMem_Banks_Properties_t ActualBankProperties = { .factoryBank = { .bankSize = 0, .bankAddress = 0 }, .userBank = { .bankSize = 0, .bankAddress = 0 }, }; #if AT45DBXXX_POWER_MANAGEMENT || AT45DBXXX_RESET_MANAGEMENT || AT45DBXXX_HW_WR_PROTECT const ExtMemPins_Handle_AT45_t ExtMemPinsHandle_AT45 = { #if AT45DBXXX_POWER_MANAGEMENT .SetPinPowerOn = ExtMem_SetPinPowerOn, .SetPinPowerOff = ExtMem_SetPinPowerOff, #endif #if AT45DBXXX_RESET_MANAGEMENT .ResetPinAssert = ExtMem_ResetPinAssert, .ResetPinRelease = ExtMem_ResetPinRelease, #endif #if AT45DBXXX_HW_WR_PROTECT .HwWrProtPinAssert = ExtMem_HwWrProtPinAssert, .HwWrProtPinRelease = ExtMem_HwWrProtPinRelease, #endif }; #endif #if W25QXXX_POWER_MANAGEMENT || W25QXXX_RESET_MANAGEMENT || W25QXXX_HW_WR_PROTECT const ExtMemPins_Handle_W25Q_t ExtMemPinsHandle_W25Q = { #if W25QXXX_POWER_MANAGEMENT .SetPinPowerOn = ExtMem_SetPinPowerOn, .SetPinPowerOff = ExtMem_SetPinPowerOff, #endif #if W25QXXX_RESET_MANAGEMENT .ResetPinAssert = ExtMem_ResetPinAssert, .ResetPinRelease = ExtMem_ResetPinRelease, #endif #if W25QXXX_HW_WR_PROTECT .HwWrProtPinAssert = ExtMem_HwWrProtPinAssert, .HwWrProtPinRelease = ExtMem_HwWrProtPinRelease, #endif }; #endif static const char Malfunction_FlashProperties_Description[] = ""; static const flash_properties_t Malfunction_FlashProperties = { .minAddress = 0, .maxAddress = 0, .maxSectors = 0, .sectorSize = 0, .pChipDescription = Malfunction_FlashProperties_Description, }; static const ExtMem_Banks_Properties_t Malfunction_BanksProperties = { .factoryBankSize = 0, .userBankSize = 0, .factoryBankAddress = 0, .userBankAddress = 0, }; // Function stub static bool Malfunction_ExtMem_Write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { return false; } // Function stub static bool Malfunction_ExtMem_Read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { return false; } // Function stub static bool Malfunction_ExtMem_RangeCheck_Read( flash_address_t address, flash_address_t size ) { return false; } // Function stub static bool Malfunction_ExtMem_RangeCheck_Write( flash_address_t address, flash_address_t size ) { return false; } // Function stub static bool Malfunction_ExtMem_BankProtect( eExtMem_Bank_t bankId, bool protectStatus ) { return false; } // Function stub static bool Malfunction_ExtMem_CheckBankProtect( eExtMem_Bank_t bankId, bool * pActualProtectStatus ) { return false; } // Exporting External Memory descriptor ExtMem_Handle_t ExtMemHandle = { .Init = ExtMem_Init, // Always set to actual value .Write = Malfunction_ExtMem_Write, // will be set after Init() .Read = Malfunction_ExtMem_Read, // will be set after Init() .RangeCheck_Read = Malfunction_ExtMem_RangeCheck_Read, // will be set after Init() .RangeCheck_Write = Malfunction_ExtMem_RangeCheck_Write, // will be set after Init() .BankProtect = Malfunction_ExtMem_BankProtect, // will be set after Init() .CheckBankProtect = Malfunction_ExtMem_CheckBankProtect, // will be set after Init() .DeInit = ExtMem_DeInit, // Always set to actual value .pFlashProperties = &Malfunction_FlashProperties, // will be set after Init() .pBanksProperties = &Malfunction_BanksProperties // will be set after Init() }; // // Current Model Memory Template: Bank 0 (Factory) // // [WRONG] // #warning Remove this line as soon as the following entity has been validated // const static sMemoryBankingTemplate_t ACMMemory_Bank0 = { // // .selectRegister = { // .loprotect = 0x000000FE, // First 4MBit (actually 7MBit, the bigger the better) // // First Sector 0 is skipped, and Sectors 1..7 is used as Bank0. // // Each sector = 128KBytes // .hiprotect = 0x00000000, // } // // }; // // // 16MBit flash AT45DB161E is installed; // // But the application supposes that only 8MBit (4+4Mbits) is presents. // // So it adresses first 4MBit as a factory bank, and the second as // // a user bank. The rest part is useless. // // // Current Model Memory Template: Bank 1 (User) // // [WRONG] // #warning Remove this line as soon as the following entity has been validated // const static sMemoryBankingTemplate_t ACMMemory_Bank1 = { // // .selectRegister = { // .loprotect = 0x0000FF00, // Second 4MBit (actually 8MBit, the bigger the better) // // Sectors 8..15 is used as Bank1. // .hiprotect = 0x00000000, // } // // }; // @ACMMemory_BankX: Dynamically filled template for sector protection operation static sMemoryBankingTemplate_t ACMMemory_BankX; // ExtMem_DeInit() // De-Initializes external memory driver. // Makes the chip fall asleep. // @bForce: if 'false' the function will detect if the chip // is busy and interrupt the operation with error. // If 'true', the function ignores current chip state and makes it // fall asleep instantly. // Returns 'true' in success case, and 'false' otherwise. bool ExtMem_DeInit( bool bForce ) { // Clear status bExtMemStatus = false; // Check if the driver is loaded if( NULL != flashDriver ) { #if EXTMEM_HIBERNATE_ENABLED // Make flash chip fall asleep if( FLASH_ERROR( flashDriver->api->routines.flashFinalize( true, bForce ) ) ) #else // Deinitialize driver if( FLASH_ERROR( flashDriver->api->routines.flashFinalize( false, bForce ) ) ) #endif { return false; } } // de-initialize SPI driver pSPIHandle->DeInit(); // De-Initialize power- and reset- management pins ExtMem_Pins_Deinit(); // clear routines and data ExtMemHandle.Write = Malfunction_ExtMem_Write; ExtMemHandle.Read = Malfunction_ExtMem_Read; ExtMemHandle.RangeCheck_Read = Malfunction_ExtMem_RangeCheck_Read; ExtMemHandle.RangeCheck_Write = Malfunction_ExtMem_RangeCheck_Write; ExtMemHandle.BankProtect = Malfunction_ExtMem_BankProtect; ExtMemHandle.CheckBankProtect = Malfunction_ExtMem_CheckBankProtect; ExtMemHandle.pFlashProperties = &Malfunction_FlashProperties; ExtMemHandle.pBanksProperties = &Malfunction_BanksProperties; // set status and return return true; } // ExtMem_DriverLoad // Detects the chip on the bus and returns the appropriate driver to control it static const ExtMemDriver_t * ExtMem_DriverLoad() { for( size_t flash_driver_active = 0; flash_driver_active < sizeof(flash_drivers)/sizeof(flash_drivers[0]); ++flash_driver_active ) { if( FLASH_SUCCESS(flash_drivers[ flash_driver_active ].api->routines.flashInitialize( true ) ) ) { return &flash_drivers[ flash_driver_active ]; } } return NULL; // driver not found } // ExtMem_Init() // Initializes external memory driver. // Wakes the memory chip up if it is necessary. // Returns 'true' in success case, and 'false' otherwise. bool ExtMem_Init() { // Clear status bExtMemStatus = false; // Initialize power- and reset- management pins ExtMem_Pins_Init(); // initialize SPI driver pSPIHandle->Init(); // Detect chip and load driver flashDriver = ExtMem_DriverLoad(); // Check if the driver is loaded if( NULL == flashDriver ) { // deinitialize power- and reset- management pins ExtMem_Pins_Deinit(); // de-initialize SPI driver pSPIHandle->DeInit(); return false; } // Check boundaries if( flashDriver->api->flashProperties->minAddress >= flashDriver->api->flashProperties->maxAddress ) return false; // Check sizes if( flashDriver->api->flashProperties->maxSectors == 0 || flashDriver->api->flashProperties->sectorSize == 0 ) return false; // Update banks properties with actual values ActualBankProperties.factoryBankSize = EXTMEM_BANK0_SIZE; ActualBankProperties.userBankSize = EXTMEM_BANK1_SIZE; ActualBankProperties.factoryBankAddress = flashDriver->api->flashProperties->minAddress; ActualBankProperties.userBankAddress = flashDriver->api->flashProperties->minAddress + ActualBankProperties.factoryBankSize; // Check the Bank sizes: // the banks can not share one sector, the sector can be owned by only one bank. if( ((ActualBankProperties.factoryBankSize % flashDriver->api->flashProperties->sectorSize > 0 )?(flashDriver->api->flashProperties->sectorSize):(0)) +((ActualBankProperties.userBankSize % flashDriver->api->flashProperties->sectorSize > 0 )?(flashDriver->api->flashProperties->sectorSize):(0)) +( ActualBankProperties.factoryBankSize + ActualBankProperties.userBankSize) > flashDriver->api->flashProperties->maxSectors * flashDriver->api->flashProperties->sectorSize ) { return false; } // initialize driver routines and data ExtMemHandle.Write = ExtMem_Write; ExtMemHandle.Read = ExtMem_Read; ExtMemHandle.RangeCheck_Read = ExtMem_RangeCheck_Read; ExtMemHandle.RangeCheck_Write = ExtMem_RangeCheck_Write; ExtMemHandle.BankProtect = ExtMem_BankProtect; ExtMemHandle.CheckBankProtect = ExtMem_CheckBankProtect; ExtMemHandle.pFlashProperties = flashDriver->api->flashProperties; ExtMemHandle.pBanksProperties = &ActualBankProperties; // Initialize flash driver if( FLASH_ERROR( flashDriver->api->routines.flashInitialize(false) ) ) { // finalize after initialization fail flashDriver->api->routines.flashFinalize( false, true ); // deinitialize power- and reset- management pins ExtMem_Pins_Deinit(); // de-initialize SPI driver pSPIHandle->DeInit(); // flash driver initialization error return false; } // set status and return return (bExtMemStatus = true); } // ExtMem_Internal_FillBankingTemplate // Calculates the sMemoryBankingTemplate_t structure during run-time. // Function relies on the bank properties passed in @pBankProperties. static void ExtMem_Internal_FillBankingTemplate( const ExtMem_Bank_Properties_t * pBankProperties, sMemoryBankingTemplate_t * pFactoryProtectionTemplate ) { // The first bank's sector (including the sector) size_t factoryBankSectorBegin = __FLASH_ADDRESS2SECTOR_BEGIN(pBankProperties->bankAddress, ExtMemHandle.pFlashProperties->sectorSize); // The last bank's sector (including the sector) size_t factoryBankSectorEnd = __FLASH_ADDRESS2SECTOR_END(pBankProperties->bankAddress + pBankProperties->bankSize, ExtMemHandle.pFlashProperties->sectorSize); // Fill the structure with zeros before operation for( size_t nZero = 0; nZero < sizeof(pFactoryProtectionTemplate->selectRegister); ++nZero ) { pFactoryProtectionTemplate->selectRegister.bytes[nZero] = 0; } // Mark the affected sectors in the output structure for( size_t nSector = factoryBankSectorBegin; nSector < factoryBankSectorEnd; ++nSector ) { BITBUFFER_SET( pFactoryProtectionTemplate->selectRegister.bytes, nSector ); } } // Initialize ExtMem power- and reset- management GPIO-pins static void ExtMem_Pins_Init() { #if W25QXXX_RESET_MANAGEMENT || AT45DBXXX_RESET_MANAGEMENT // Configure GPIO pins for AT45 IC : reset signal GPIO_InitTypeDef GPIO_InitStruct = {0}; // Configure as input to detect actual level: GPIO_InitStruct.Pin = CONFIG_PIN__EXTMEM__RST; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(CONFIG_PORT__EXTMEM__RST, &GPIO_InitStruct); // read actual level GPIO_PinState xPreservedState = HAL_GPIO_ReadPin( CONFIG_PORT__EXTMEM__RST, CONFIG_PIN__EXTMEM__RST ); // Configure as analog GPIO_InitStruct.Pin = CONFIG_PIN__EXTMEM__RST; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(CONFIG_PORT__EXTMEM__RST, &GPIO_InitStruct); // prepare pin state: HAL_GPIO_WritePin( CONFIG_PORT__EXTMEM__RST, CONFIG_PIN__EXTMEM__RST, xPreservedState ); // Configure as output: GPIO_InitStruct.Pin = CONFIG_PIN__EXTMEM__RST; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(CONFIG_PORT__EXTMEM__RST, &GPIO_InitStruct); #endif } // De-Initialize ExtMem power- and reset- management GPIO-pins static void ExtMem_Pins_Deinit() { #if W25QXXX_RESET_MANAGEMENT || AT45DBXXX_RESET_MANAGEMENT // Configure GPIO pins for AT45 IC : PB10=nWP (reset signal) GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = CONFIG_PIN__EXTMEM__RST; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(CONFIG_PORT__EXTMEM__RST, &GPIO_InitStruct); #endif } typedef struct { // Actual protection bits for all sectors: __FLASH_DWORD actual_protection_mask_lo; __FLASH_DWORD actual_protection_mask_hi; // Desired protection bits for selected sectors: __FLASH_DWORD desired_protection_mask_lo; __FLASH_DWORD desired_protection_mask_hi; union { bool globalProtectionStatus; // AT25 bool anySectorProtectionStatus; // W25Q }; bool individualProtectionStatus; } sProtectionEntry_t; // Queries actual protection information from the flash-memory and fills the [sProtectionEntry_t] structure. // If required, fills the protection register that can be used to set the protection information // @bankId = memory bank identifier; // @desiredProtectStatus = desired protecion state // @protEntry = pointer to the [sProtectionEntry_t] structure to fill, mandatory. // @setProtectRegister = pointer to the set-protection register to fill, optional, it then can be used by flash_protect_ex() // Returns the operaion status, true if succeded, false otherwise. // The actual protection state will be returned in @protEntry. static bool ExtMem_Internal_FillProtectionEntry( eExtMem_Bank_t bankId, bool desiredProtectStatus, sProtectionEntry_t * pProtEntry, flash_api_protect_t * setProtectRegister ) { sMemoryBankingTemplate_t * pBankTemplate = NULL; flash_api_getprotect_t getProtectRegister; // Check if the driver is loaded if( NULL == flashDriver ) return false; if( NULL != pProtEntry ) { // This function uses individual sector protecton // switch( bankId ) { case extmem_bank_factory: { pBankTemplate = &ACMMemory_BankX; // use dynamic template for FACTORY bank ExtMem_Internal_FillBankingTemplate( &ExtMemHandle.pBanksProperties->factoryBank, pBankTemplate ); } break; case extmem_bank_user: { pBankTemplate = &ACMMemory_BankX; // use dynamic template for USER bank ExtMem_Internal_FillBankingTemplate( &ExtMemHandle.pBanksProperties->userBank, pBankTemplate ); } break; } if( NULL != pBankTemplate ) { // Retrieve currect sector protection register: if( FLASH_SUCCESS( flashDriver->api->routines.flashGetProtect( &getProtectRegister ) ) ) { // Get actual protection bits for all sectors: pProtEntry->actual_protection_mask_lo = getProtectRegister.sectors.loprotect; pProtEntry->actual_protection_mask_hi = getProtectRegister.sectors.hiprotect; // Initialize desired protection bits for selected sectors: pProtEntry->desired_protection_mask_lo = ((desiredProtectStatus)?0xFFFFFFFF:0x00000000); pProtEntry->desired_protection_mask_hi = ((desiredProtectStatus)?0xFFFFFFFF:0x00000000); // Filter only selected sectors (specified by selection register on memory bank template) pProtEntry->actual_protection_mask_lo &= pBankTemplate->selectRegister.loprotect; pProtEntry->actual_protection_mask_hi &= pBankTemplate->selectRegister.hiprotect; pProtEntry->desired_protection_mask_lo &= pBankTemplate->selectRegister.loprotect; pProtEntry->desired_protection_mask_hi &= pBankTemplate->selectRegister.hiprotect; // Compare actual and desired sector protection status: if( pProtEntry->actual_protection_mask_lo != pProtEntry->desired_protection_mask_lo || pProtEntry->actual_protection_mask_hi != pProtEntry->desired_protection_mask_hi ) { // PROTECTION STATUS: SOME SECTORS HAVE INCORRECT PROTECTION FLAGS pProtEntry->individualProtectionStatus = false; if( NULL != setProtectRegister ) { // Do not change COMMON PROTECTION FLAG: setProtectRegister->protection_modify = flash_sector_protect_nomodify; // Mark selected sectors to be protected: setProtectRegister->protection_enabled = flash_sector_protect_pick; // Copy sectors selection mask: setProtectRegister->sectors.loprotect = pBankTemplate->selectRegister.loprotect; setProtectRegister->sectors.hiprotect = pBankTemplate->selectRegister.hiprotect; } } else { // PROTECTION STATUS: ALL SECTORS HAVE CORRECT PROTECTION FLAGS pProtEntry->individualProtectionStatus = true; } // QUERY GLOBAL PROTECTION FLAG switch( flashDriver->api->routines.flashGetProtect( NULL ) ) { case FLERR_PROTECT_ENABLED: pProtEntry->globalProtectionStatus = true; return true; case FLERR_PROTECT_DISABLED: pProtEntry->globalProtectionStatus = false; return true; } } } } return false; } // ExtMem_BankProtect() // Implements external memory protection by Memory Bank Identifier // @bankId = memory bank identifier; // @desiredProtectStatus - protection status (true=protected, false=unprotected) // Returns the result of operation static bool ExtMem_BankProtect( eExtMem_Bank_t bankId, bool desiredProtectStatus ) { sProtectionEntry_t protEntry_Bank0; // protection information for Bank0 sProtectionEntry_t protEntry_Bank1; // protection information for Bank1 // Check if the driver is loaded if( NULL == flashDriver ) return false; // -------------------- if( extmem_bank_factory != bankId && extmem_bank_user != bankId ) { return false; // error } // -------------------- // Query actual protection information for both banks // Argument ExtMem_Internal_FillProtectionEntry(... @desiredProtectStatus = true ...): // that ensures that all sectors are protected with individual protection flags. if( ExtMem_Internal_FillProtectionEntry( extmem_bank_factory, true, &protEntry_Bank0, NULL ) && ExtMem_Internal_FillProtectionEntry( extmem_bank_user, true, &protEntry_Bank1, NULL ) ) { // Actual bank's protection state is depends on the global protection state and the individual protection state for bank bool stateBank0 = ( protEntry_Bank0.individualProtectionStatus && protEntry_Bank0.globalProtectionStatus ); bool stateBank1 = ( protEntry_Bank1.individualProtectionStatus && protEntry_Bank1.globalProtectionStatus ); // Check if current bank's protection state matchs to desired state if( (( extmem_bank_factory == bankId ) && ( desiredProtectStatus == stateBank0 )) || (( extmem_bank_user == bankId ) && ( desiredProtectStatus == stateBank1 )) ) { // All bank's protection statuses are correct, no operations are required return true; // success } else // Only if current state and the desired state mismatch: { // The global protection state must be set if at least one bank must be protected. bool requiredGlobalState = (( extmem_bank_factory == bankId )?desiredProtectStatus:stateBank0) || (( extmem_bank_user == bankId )?desiredProtectStatus:stateBank1); if( requiredGlobalState ) { // If global protection state will be set // Ensure that all banks have correct individual sector protection flags: // Remember: @requiredGlobalState is true if( protEntry_Bank0.individualProtectionStatus != (( extmem_bank_factory == bankId )?desiredProtectStatus:stateBank0) ) { // @individualProtectionStatus does not match to the desired state flash_api_protect_t setProtectRegister; // set-protection register // new bank protection status stateBank0 = !protEntry_Bank0.individualProtectionStatus; // Query actual protection information for both banks // Specify argument ExtMem_Internal_FillProtectionEntry(... @desiredProtectStatus ...) to // the inverted @individualProtectionStatus state, because current @individualProtectionStatus value is wrong if( !ExtMem_Internal_FillProtectionEntry( extmem_bank_factory, stateBank0, &protEntry_Bank0, &setProtectRegister ) ) { // query error return false; } // Execute operation: modify only individual sectors protection marks to the desired state if( FLASH_ERROR( flashDriver->api->routines.flashProtectEx( &setProtectRegister, (( stateBank0 )?(flash_sector_protected):(flash_sector_unprotected)) ) ) ) { // Error: can not modify individual sector protection flags return false; } } if( protEntry_Bank1.individualProtectionStatus != (( extmem_bank_user == bankId )?desiredProtectStatus:stateBank1) ) { // @individualProtectionStatus does not match to the desired state flash_api_protect_t setProtectRegister; // set-protection register // new bank protection status stateBank1 = !protEntry_Bank1.individualProtectionStatus; // Query actual protection information for both banks // Specify argument ExtMem_Internal_FillProtectionEntry(... @desiredProtectStatus ...) to // the inverted @individualProtectionStatus state, because current @individualProtectionStatus value is wrong if( !ExtMem_Internal_FillProtectionEntry( extmem_bank_user, stateBank1, &protEntry_Bank1, &setProtectRegister ) ) { // query error return false; } // Execute operation: modify only individual sectors protection marks to the desired state if( FLASH_ERROR( flashDriver->api->routines.flashProtectEx( &setProtectRegister, (( stateBank1 )?(flash_sector_protected):(flash_sector_unprotected)) ) ) ) { // Error: can not modify individual sector protection flags return false; } } // Modify global write-protection flag: protected // W25Q: stub call, always return FLERR_SUCCESS return FLASH_SUCCESS( flashDriver->api->routines.flashProtect( NULL ) ); } else { // If global protection state will be reset: all banks must be unprotected // Modify global write-protection flag: unprotected return FLASH_SUCCESS( flashDriver->api->routines.flashUnprotect( NULL ) ); } } } return false; // error } // ExtMem_CheckBankProtect() // Implements external memory protection by Memory Bank Identifier // @bankId = memory bank identifier; // @pActualProtectStatus - pointer to the boolean variable to receive actual protection status // Returns the result of operation static bool ExtMem_CheckBankProtect( eExtMem_Bank_t bankId, bool * pActualProtectStatus ) { sProtectionEntry_t protEntry; if( NULL != pActualProtectStatus ) { // Query current protection information if( ExtMem_Internal_FillProtectionEntry( bankId, true, &protEntry, NULL ) ) { *pActualProtectStatus = (protEntry.globalProtectionStatus) && (protEntry.individualProtectionStatus); return true; // success, no operations are required } } return false; // error } #if AT45DBXXX_POWER_MANAGEMENT // Implement ExtMem power-management: set power enable pin static void ExtMem_SetPinPowerOn() { #error Not-implemented } // Implement ExtMem power-management: set power disable pin static void ExtMem_SetPinPowerOff() { #error Not-implemented } #endif #if AT45DBXXX_RESET_MANAGEMENT // Implement ExtMem reset-management: set reset enable pin static void ExtMem_ResetPinAssert() { HAL_GPIO_WritePin( CONFIG_PORT__EXTMEM__RST, CONFIG_PIN__EXTMEM__RST, GPIO_PIN_RESET ); } // Implement ExtMem reset-management: set reset disable pin static void ExtMem_ResetPinRelease() { HAL_GPIO_WritePin( CONFIG_PORT__EXTMEM__RST, CONFIG_PIN__EXTMEM__RST, GPIO_PIN_SET ); } #endif #if AT45DBXXX_HW_WR_PROTECT // Implement ExtMem hardware-write-protection: enable write protection static void ExtMem_HwWrProtPinAssert() { #error Not-implemented } // Implement ExtMem hardware-write-protection: disable write protection static void ExtMem_HwWrProtPinRelease() { #error Not-implemented } #endif #if CONFIG_EXTMEM_EMULATEWRITE static bool ExtMem_Write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { return true; } #else static bool ExtMem_Write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // Check if the driver is loaded if( NULL == flashDriver ) return false; extern volatile bool bExtMemStatus; return bExtMemStatus && FLASH_SUCCESS( flashDriver->api->routines.flashWrite( flashDriver->api->flashProperties->minAddress + address, pBuffer, size, fwm_safewrite ) ); } #endif #if CONFIG_EXTMEM_EMULATEREAD static bool ExtMem_Read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { memset( pBuffer, 0xDE, size ); return true; } #else static bool ExtMem_Read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // Check if the driver is loaded if( NULL == flashDriver ) return false; extern volatile bool bExtMemStatus; return bExtMemStatus && FLASH_SUCCESS( flashDriver->api->routines.flashRead( flashDriver->api->flashProperties->minAddress + address, pBuffer, size ) ); } #endif static bool ExtMem_RangeCheck_Read( flash_address_t address, flash_address_t size ) { // Check if the driver is loaded if( NULL == flashDriver ) return false; if( size <= (flashDriver->api->flashProperties->maxAddress - flashDriver->api->flashProperties->minAddress) ) { if( address < flashDriver->api->flashProperties->maxAddress - flashDriver->api->flashProperties->minAddress - size ) { return true; } } return false; } static bool ExtMem_RangeCheck_Write( flash_address_t address, flash_address_t size ) { // Check if the driver is loaded if( NULL == flashDriver ) return false; if( size <= (flashDriver->api->flashProperties->maxAddress - flashDriver->api->flashProperties->minAddress) ) { if( address < flashDriver->api->flashProperties->maxAddress - flashDriver->api->flashProperties->minAddress - size ) { return true; } } return false; } // legacy compatibility flash_err_t flash_read( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size ) { // Check if the driver is loaded if( NULL == flashDriver ) return FLERR_DEVICE_MALFUNCTION; extern volatile bool bExtMemStatus; if( bExtMemStatus ) return flashDriver->api->routines.flashRead( address, pBuffer, size ); return FLERR_DEVICE_MALFUNCTION; // !bExtMemStatus } // legacy compatibility flash_err_t flash_write( flash_address_t address, __FLASH_BYTE * pBuffer, flash_address_t size, flash_write_mode_t unused ) { // Check if the driver is loaded if( NULL == flashDriver ) return FLERR_DEVICE_MALFUNCTION; extern volatile bool bExtMemStatus; (void)unused; if( bExtMemStatus ) return flashDriver->api->routines.flashWrite( address, pBuffer, size, fwm_safewrite ); return FLERR_DEVICE_MALFUNCTION; // !bExtMemStatus }