Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers FlashIAP.cpp Source File

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