Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
FlashIAP.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017-2019 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 int FlashIAP::init() 00050 { 00051 int ret = 0; 00052 _mutex->lock(); 00053 { 00054 ScopedRamExecutionLock make_ram_executable; 00055 ScopedRomWriteLock make_rom_writable; 00056 if (flash_init(&_flash)) { 00057 ret = -1; 00058 } 00059 } 00060 uint32_t page_size = get_page_size(); 00061 _page_buf = new uint8_t[page_size]; 00062 00063 _mutex->unlock(); 00064 return ret; 00065 } 00066 00067 int FlashIAP::deinit() 00068 { 00069 int ret = 0; 00070 _mutex->lock(); 00071 { 00072 ScopedRamExecutionLock make_ram_executable; 00073 ScopedRomWriteLock make_rom_writable; 00074 if (flash_free(&_flash)) { 00075 ret = -1; 00076 } 00077 } 00078 delete[] _page_buf; 00079 _mutex->unlock(); 00080 return ret; 00081 } 00082 00083 00084 int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size) 00085 { 00086 int32_t ret = -1; 00087 _mutex->lock(); 00088 { 00089 ScopedRamExecutionLock make_ram_executable; 00090 ScopedRomWriteLock make_rom_writable; 00091 ret = flash_read(&_flash, addr, (uint8_t *) buffer, size); 00092 } 00093 _mutex->unlock(); 00094 return ret; 00095 } 00096 00097 int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size) 00098 { 00099 uint32_t page_size = get_page_size(); 00100 uint32_t flash_size = flash_get_size(&_flash); 00101 uint32_t flash_start_addr = flash_get_start_address(&_flash); 00102 uint8_t flash_erase_value = flash_get_erase_value(&_flash); 00103 uint32_t chunk, prog_size; 00104 const uint8_t *buf = (uint8_t *) buffer; 00105 const uint8_t *prog_buf; 00106 00107 // addr should be aligned to page size 00108 if (!is_aligned(addr, page_size) || (!buffer) || 00109 ((addr + size) > (flash_start_addr + flash_size))) { 00110 return -1; 00111 } 00112 00113 int ret = 0; 00114 _mutex->lock(); 00115 while (size && !ret) { 00116 uint32_t current_sector_size = flash_get_sector_size(&_flash, addr); 00117 bool unaligned_src = (((size_t) buf / sizeof(uint32_t) * sizeof(uint32_t)) != (size_t) buf); 00118 chunk = std::min(current_sector_size - (addr % current_sector_size), size); 00119 // Need to use the internal page buffer in any of these two cases: 00120 // 1. Size is not page aligned 00121 // 2. Source buffer is not aligned to uint32_t. This is not supported by many targets (although 00122 // the pointer they accept is of uint8_t). 00123 if (unaligned_src || (chunk < page_size)) { 00124 chunk = std::min(chunk, page_size); 00125 memcpy(_page_buf, buf, chunk); 00126 if (chunk < page_size) { 00127 memset(_page_buf + chunk, flash_erase_value, page_size - chunk); 00128 } 00129 prog_buf = _page_buf; 00130 prog_size = page_size; 00131 } else { 00132 chunk = chunk / page_size * page_size; 00133 prog_buf = buf; 00134 prog_size = chunk; 00135 } 00136 { 00137 // Few boards may fail the write actions due to HW limitations (like critical drivers that 00138 // disable flash operations). Just retry a few times until success. 00139 for (unsigned int retry = 0; retry < num_write_retries; retry++) { 00140 ScopedRamExecutionLock make_ram_executable; 00141 ScopedRomWriteLock make_rom_writable; 00142 ret = flash_program_page(&_flash, addr, prog_buf, prog_size); 00143 if (ret) { 00144 ret = -1; 00145 } else { 00146 break; 00147 } 00148 } 00149 } 00150 size -= chunk; 00151 addr += chunk; 00152 buf += chunk; 00153 } 00154 _mutex->unlock(); 00155 00156 return ret; 00157 } 00158 00159 bool FlashIAP::is_aligned_to_sector(uint32_t addr, uint32_t size) 00160 { 00161 uint32_t current_sector_size = flash_get_sector_size(&_flash, addr); 00162 if (!is_aligned(size, current_sector_size) || 00163 !is_aligned(addr, current_sector_size)) { 00164 return false; 00165 } else { 00166 return true; 00167 } 00168 } 00169 00170 int FlashIAP::erase(uint32_t addr, uint32_t size) 00171 { 00172 uint32_t current_sector_size; 00173 uint32_t flash_size = flash_get_size(&_flash); 00174 uint32_t flash_start_addr = flash_get_start_address(&_flash); 00175 uint32_t flash_end_addr = flash_start_addr + flash_size; 00176 uint32_t erase_end_addr = addr + size; 00177 00178 if (erase_end_addr > flash_end_addr) { 00179 return -1; 00180 } else if (erase_end_addr < flash_end_addr) { 00181 uint32_t following_sector_size = flash_get_sector_size(&_flash, erase_end_addr); 00182 if (!is_aligned(erase_end_addr, following_sector_size)) { 00183 return -1; 00184 } 00185 } 00186 00187 int32_t ret = 0; 00188 _mutex->lock(); 00189 while (size && !ret) { 00190 // Few boards may fail the erase actions due to HW limitations (like critical drivers that 00191 // disable flash operations). Just retry a few times until success. 00192 for (unsigned int retry = 0; retry < num_write_retries; retry++) { 00193 ScopedRamExecutionLock make_ram_executable; 00194 ScopedRomWriteLock make_rom_writable; 00195 ret = flash_erase_sector(&_flash, addr); 00196 if (ret) { 00197 ret = -1; 00198 } else { 00199 break; 00200 } 00201 } 00202 current_sector_size = flash_get_sector_size(&_flash, addr); 00203 size -= current_sector_size; 00204 addr += current_sector_size; 00205 } 00206 _mutex->unlock(); 00207 return ret; 00208 } 00209 00210 uint32_t FlashIAP::get_page_size() const 00211 { 00212 return flash_get_page_size(&_flash); 00213 } 00214 00215 uint32_t FlashIAP::get_sector_size(uint32_t addr) const 00216 { 00217 return flash_get_sector_size(&_flash, addr); 00218 } 00219 00220 uint32_t FlashIAP::get_flash_start() const 00221 { 00222 return flash_get_start_address(&_flash); 00223 } 00224 00225 uint32_t FlashIAP::get_flash_size() const 00226 { 00227 return flash_get_size(&_flash); 00228 } 00229 00230 uint8_t FlashIAP::get_erase_value() const 00231 { 00232 return flash_get_erase_value(&_flash); 00233 } 00234 00235 } 00236 00237 #endif
Generated on Tue Jul 12 2022 13:54:22 by
