mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
FlashIAP.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017 ARM Limited 00003 * 00004 * Permission is hereby granted, free of charge, to any person obtaining a copy 00005 * of this software and associated documentation files (the "Software"), to deal 00006 * in the Software without restriction, including without limitation the rights 00007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 * copies of the Software, and to permit persons to whom the Software is 00009 * furnished to do so, subject to the following conditions: 00010 * 00011 * The above copyright notice and this permission notice shall be included in 00012 * all copies or substantial portions of the Software. 00013 * 00014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00020 * SOFTWARE. 00021 */ 00022 00023 #include <stdio.h> 00024 #include <string.h> 00025 #include <algorithm> 00026 #include "FlashIAP.h" 00027 #include "platform/mbed_assert.h" 00028 #include "platform/ScopedRamExecutionLock.h" 00029 #include "platform/ScopedRomWriteLock.h" 00030 00031 00032 #if DEVICE_FLASH 00033 00034 namespace mbed { 00035 00036 const unsigned int num_write_retries = 16; 00037 00038 SingletonPtr<PlatformMutex> FlashIAP::_mutex; 00039 00040 static inline bool is_aligned(uint32_t number, uint32_t alignment) 00041 { 00042 if ((number % alignment) != 0) { 00043 return false; 00044 } else { 00045 return true; 00046 } 00047 } 00048 00049 FlashIAP::FlashIAP() 00050 { 00051 00052 } 00053 00054 FlashIAP::~FlashIAP() 00055 { 00056 00057 } 00058 00059 int FlashIAP::init() 00060 { 00061 int ret = 0; 00062 _mutex->lock(); 00063 { 00064 ScopedRamExecutionLock make_ram_executable; 00065 ScopedRomWriteLock make_rom_writable; 00066 if (flash_init(&_flash)) { 00067 ret = -1; 00068 } 00069 } 00070 uint32_t page_size = get_page_size(); 00071 _page_buf = new uint8_t[page_size]; 00072 00073 _mutex->unlock(); 00074 return ret; 00075 } 00076 00077 int FlashIAP::deinit() 00078 { 00079 int ret = 0; 00080 _mutex->lock(); 00081 { 00082 ScopedRamExecutionLock make_ram_executable; 00083 ScopedRomWriteLock make_rom_writable; 00084 if (flash_free(&_flash)) { 00085 ret = -1; 00086 } 00087 } 00088 delete[] _page_buf; 00089 _mutex->unlock(); 00090 return ret; 00091 } 00092 00093 00094 int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size) 00095 { 00096 int32_t ret = -1; 00097 _mutex->lock(); 00098 { 00099 ScopedRamExecutionLock make_ram_executable; 00100 ScopedRomWriteLock make_rom_writable; 00101 ret = flash_read(&_flash, addr, (uint8_t *) buffer, size); 00102 } 00103 _mutex->unlock(); 00104 return ret; 00105 } 00106 00107 int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size) 00108 { 00109 uint32_t page_size = get_page_size(); 00110 uint32_t flash_size = flash_get_size(&_flash); 00111 uint32_t flash_start_addr = flash_get_start_address(&_flash); 00112 uint32_t chunk, prog_size; 00113 const uint8_t *buf = (uint8_t *) buffer; 00114 const uint8_t *prog_buf; 00115 00116 // addr should be aligned to page size 00117 if (!is_aligned(addr, page_size) || (!buffer) || 00118 ((addr + size) > (flash_start_addr + flash_size))) { 00119 return -1; 00120 } 00121 00122 int ret = 0; 00123 _mutex->lock(); 00124 while (size && !ret) { 00125 uint32_t current_sector_size = flash_get_sector_size(&_flash, addr); 00126 bool unaligned_src = (((size_t) buf / sizeof(uint32_t) * sizeof(uint32_t)) != (size_t) buf); 00127 chunk = std::min(current_sector_size - (addr % current_sector_size), size); 00128 // Need to use the internal page buffer in any of these two cases: 00129 // 1. Size is not page aligned 00130 // 2. Source buffer is not aligned to uint32_t. This is not supported by many targets (although 00131 // the pointer they accept is of uint8_t). 00132 if (unaligned_src || (chunk < page_size)) { 00133 chunk = std::min(chunk, page_size); 00134 memcpy(_page_buf, buf, chunk); 00135 if (chunk < page_size) { 00136 memset(_page_buf + chunk, 0xFF, page_size - chunk); 00137 } 00138 prog_buf = _page_buf; 00139 prog_size = page_size; 00140 } else { 00141 chunk = chunk / page_size * page_size; 00142 prog_buf = buf; 00143 prog_size = chunk; 00144 } 00145 { 00146 // Few boards may fail the write actions due to HW limitations (like critical drivers that 00147 // disable flash operations). Just retry a few times until success. 00148 for (unsigned int retry = 0; retry < num_write_retries; retry++) { 00149 ScopedRamExecutionLock make_ram_executable; 00150 ScopedRomWriteLock make_rom_writable; 00151 ret = flash_program_page(&_flash, addr, prog_buf, prog_size); 00152 if (ret) { 00153 ret = -1; 00154 } else { 00155 break; 00156 } 00157 } 00158 } 00159 size -= chunk; 00160 addr += chunk; 00161 buf += chunk; 00162 } 00163 _mutex->unlock(); 00164 00165 return ret; 00166 } 00167 00168 bool FlashIAP::is_aligned_to_sector(uint32_t addr, uint32_t size) 00169 { 00170 uint32_t current_sector_size = flash_get_sector_size(&_flash, addr); 00171 if (!is_aligned(size, current_sector_size) || 00172 !is_aligned(addr, current_sector_size)) { 00173 return false; 00174 } else { 00175 return true; 00176 } 00177 } 00178 00179 int FlashIAP::erase(uint32_t addr, uint32_t size) 00180 { 00181 uint32_t current_sector_size; 00182 uint32_t flash_size = flash_get_size(&_flash); 00183 uint32_t flash_start_addr = flash_get_start_address(&_flash); 00184 uint32_t flash_end_addr = flash_start_addr + flash_size; 00185 uint32_t erase_end_addr = addr + size; 00186 00187 if (erase_end_addr > flash_end_addr) { 00188 return -1; 00189 } else if (erase_end_addr < flash_end_addr) { 00190 uint32_t following_sector_size = flash_get_sector_size(&_flash, erase_end_addr); 00191 if (!is_aligned(erase_end_addr, following_sector_size)) { 00192 return -1; 00193 } 00194 } 00195 00196 int32_t ret = 0; 00197 _mutex->lock(); 00198 while (size && !ret) { 00199 // Few boards may fail the erase actions due to HW limitations (like critical drivers that 00200 // disable flash operations). Just retry a few times until success. 00201 for (unsigned int retry = 0; retry < num_write_retries; retry++) { 00202 ScopedRamExecutionLock make_ram_executable; 00203 ScopedRomWriteLock make_rom_writable; 00204 ret = flash_erase_sector(&_flash, addr); 00205 if (ret) { 00206 ret = -1; 00207 } else { 00208 break; 00209 } 00210 } 00211 current_sector_size = flash_get_sector_size(&_flash, addr); 00212 size -= current_sector_size; 00213 addr += current_sector_size; 00214 } 00215 _mutex->unlock(); 00216 return ret; 00217 } 00218 00219 uint32_t FlashIAP::get_page_size() const 00220 { 00221 return flash_get_page_size(&_flash); 00222 } 00223 00224 uint32_t FlashIAP::get_sector_size(uint32_t addr) const 00225 { 00226 return flash_get_sector_size(&_flash, addr); 00227 } 00228 00229 uint32_t FlashIAP::get_flash_start() const 00230 { 00231 return flash_get_start_address(&_flash); 00232 } 00233 00234 uint32_t FlashIAP::get_flash_size() const 00235 { 00236 return flash_get_size(&_flash); 00237 } 00238 00239 uint8_t FlashIAP::get_erase_value() const 00240 { 00241 return flash_get_erase_value(&_flash); 00242 } 00243 00244 } 00245 00246 #endif
Generated on Tue Jul 12 2022 20:41:14 by 1.7.2