mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

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 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