mbed-os5 only for TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Committer:
kenjiArai
Date:
Tue Dec 31 06:02:27 2019 +0000
Revision:
1:9db0e321a9f4
updated based on mbed-os5.15.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 1:9db0e321a9f4 1 /* mbed Microcontroller Library
kenjiArai 1:9db0e321a9f4 2 * Copyright (c) 2017-2019 ARM Limited
kenjiArai 1:9db0e321a9f4 3 *
kenjiArai 1:9db0e321a9f4 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
kenjiArai 1:9db0e321a9f4 5 * of this software and associated documentation files (the "Software"), to deal
kenjiArai 1:9db0e321a9f4 6 * in the Software without restriction, including without limitation the rights
kenjiArai 1:9db0e321a9f4 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
kenjiArai 1:9db0e321a9f4 8 * copies of the Software, and to permit persons to whom the Software is
kenjiArai 1:9db0e321a9f4 9 * furnished to do so, subject to the following conditions:
kenjiArai 1:9db0e321a9f4 10 *
kenjiArai 1:9db0e321a9f4 11 * The above copyright notice and this permission notice shall be included in
kenjiArai 1:9db0e321a9f4 12 * all copies or substantial portions of the Software.
kenjiArai 1:9db0e321a9f4 13 *
kenjiArai 1:9db0e321a9f4 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
kenjiArai 1:9db0e321a9f4 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
kenjiArai 1:9db0e321a9f4 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
kenjiArai 1:9db0e321a9f4 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
kenjiArai 1:9db0e321a9f4 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
kenjiArai 1:9db0e321a9f4 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
kenjiArai 1:9db0e321a9f4 20 * SOFTWARE.
kenjiArai 1:9db0e321a9f4 21 */
kenjiArai 1:9db0e321a9f4 22
kenjiArai 1:9db0e321a9f4 23 #include <stdio.h>
kenjiArai 1:9db0e321a9f4 24 #include <string.h>
kenjiArai 1:9db0e321a9f4 25 #include <algorithm>
kenjiArai 1:9db0e321a9f4 26 #include "FlashIAP.h"
kenjiArai 1:9db0e321a9f4 27 #include "platform/mbed_assert.h"
kenjiArai 1:9db0e321a9f4 28 #include "platform/ScopedRamExecutionLock.h"
kenjiArai 1:9db0e321a9f4 29 #include "platform/ScopedRomWriteLock.h"
kenjiArai 1:9db0e321a9f4 30
kenjiArai 1:9db0e321a9f4 31
kenjiArai 1:9db0e321a9f4 32 #if DEVICE_FLASH
kenjiArai 1:9db0e321a9f4 33
kenjiArai 1:9db0e321a9f4 34 namespace mbed {
kenjiArai 1:9db0e321a9f4 35
kenjiArai 1:9db0e321a9f4 36 const unsigned int num_write_retries = 16;
kenjiArai 1:9db0e321a9f4 37
kenjiArai 1:9db0e321a9f4 38 SingletonPtr<PlatformMutex> FlashIAP::_mutex;
kenjiArai 1:9db0e321a9f4 39
kenjiArai 1:9db0e321a9f4 40 static inline bool is_aligned(uint32_t number, uint32_t alignment)
kenjiArai 1:9db0e321a9f4 41 {
kenjiArai 1:9db0e321a9f4 42 if ((number % alignment) != 0) {
kenjiArai 1:9db0e321a9f4 43 return false;
kenjiArai 1:9db0e321a9f4 44 } else {
kenjiArai 1:9db0e321a9f4 45 return true;
kenjiArai 1:9db0e321a9f4 46 }
kenjiArai 1:9db0e321a9f4 47 }
kenjiArai 1:9db0e321a9f4 48
kenjiArai 1:9db0e321a9f4 49 int FlashIAP::init()
kenjiArai 1:9db0e321a9f4 50 {
kenjiArai 1:9db0e321a9f4 51 int ret = 0;
kenjiArai 1:9db0e321a9f4 52 _mutex->lock();
kenjiArai 1:9db0e321a9f4 53 {
kenjiArai 1:9db0e321a9f4 54 ScopedRamExecutionLock make_ram_executable;
kenjiArai 1:9db0e321a9f4 55 ScopedRomWriteLock make_rom_writable;
kenjiArai 1:9db0e321a9f4 56 if (flash_init(&_flash)) {
kenjiArai 1:9db0e321a9f4 57 ret = -1;
kenjiArai 1:9db0e321a9f4 58 }
kenjiArai 1:9db0e321a9f4 59 }
kenjiArai 1:9db0e321a9f4 60 uint32_t page_size = get_page_size();
kenjiArai 1:9db0e321a9f4 61 _page_buf = new uint8_t[page_size];
kenjiArai 1:9db0e321a9f4 62
kenjiArai 1:9db0e321a9f4 63 _mutex->unlock();
kenjiArai 1:9db0e321a9f4 64 return ret;
kenjiArai 1:9db0e321a9f4 65 }
kenjiArai 1:9db0e321a9f4 66
kenjiArai 1:9db0e321a9f4 67 int FlashIAP::deinit()
kenjiArai 1:9db0e321a9f4 68 {
kenjiArai 1:9db0e321a9f4 69 int ret = 0;
kenjiArai 1:9db0e321a9f4 70 _mutex->lock();
kenjiArai 1:9db0e321a9f4 71 {
kenjiArai 1:9db0e321a9f4 72 ScopedRamExecutionLock make_ram_executable;
kenjiArai 1:9db0e321a9f4 73 ScopedRomWriteLock make_rom_writable;
kenjiArai 1:9db0e321a9f4 74 if (flash_free(&_flash)) {
kenjiArai 1:9db0e321a9f4 75 ret = -1;
kenjiArai 1:9db0e321a9f4 76 }
kenjiArai 1:9db0e321a9f4 77 }
kenjiArai 1:9db0e321a9f4 78 delete[] _page_buf;
kenjiArai 1:9db0e321a9f4 79 _mutex->unlock();
kenjiArai 1:9db0e321a9f4 80 return ret;
kenjiArai 1:9db0e321a9f4 81 }
kenjiArai 1:9db0e321a9f4 82
kenjiArai 1:9db0e321a9f4 83
kenjiArai 1:9db0e321a9f4 84 int FlashIAP::read(void *buffer, uint32_t addr, uint32_t size)
kenjiArai 1:9db0e321a9f4 85 {
kenjiArai 1:9db0e321a9f4 86 int32_t ret = -1;
kenjiArai 1:9db0e321a9f4 87 _mutex->lock();
kenjiArai 1:9db0e321a9f4 88 {
kenjiArai 1:9db0e321a9f4 89 ScopedRamExecutionLock make_ram_executable;
kenjiArai 1:9db0e321a9f4 90 ScopedRomWriteLock make_rom_writable;
kenjiArai 1:9db0e321a9f4 91 ret = flash_read(&_flash, addr, (uint8_t *) buffer, size);
kenjiArai 1:9db0e321a9f4 92 }
kenjiArai 1:9db0e321a9f4 93 _mutex->unlock();
kenjiArai 1:9db0e321a9f4 94 return ret;
kenjiArai 1:9db0e321a9f4 95 }
kenjiArai 1:9db0e321a9f4 96
kenjiArai 1:9db0e321a9f4 97 int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size)
kenjiArai 1:9db0e321a9f4 98 {
kenjiArai 1:9db0e321a9f4 99 uint32_t page_size = get_page_size();
kenjiArai 1:9db0e321a9f4 100 uint32_t flash_size = flash_get_size(&_flash);
kenjiArai 1:9db0e321a9f4 101 uint32_t flash_start_addr = flash_get_start_address(&_flash);
kenjiArai 1:9db0e321a9f4 102 uint8_t flash_erase_value = flash_get_erase_value(&_flash);
kenjiArai 1:9db0e321a9f4 103 uint32_t chunk, prog_size;
kenjiArai 1:9db0e321a9f4 104 const uint8_t *buf = (uint8_t *) buffer;
kenjiArai 1:9db0e321a9f4 105 const uint8_t *prog_buf;
kenjiArai 1:9db0e321a9f4 106
kenjiArai 1:9db0e321a9f4 107 // addr should be aligned to page size
kenjiArai 1:9db0e321a9f4 108 if (!is_aligned(addr, page_size) || (!buffer) ||
kenjiArai 1:9db0e321a9f4 109 ((addr + size) > (flash_start_addr + flash_size))) {
kenjiArai 1:9db0e321a9f4 110 return -1;
kenjiArai 1:9db0e321a9f4 111 }
kenjiArai 1:9db0e321a9f4 112
kenjiArai 1:9db0e321a9f4 113 int ret = 0;
kenjiArai 1:9db0e321a9f4 114 _mutex->lock();
kenjiArai 1:9db0e321a9f4 115 while (size && !ret) {
kenjiArai 1:9db0e321a9f4 116 uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
kenjiArai 1:9db0e321a9f4 117 bool unaligned_src = (((size_t) buf / sizeof(uint32_t) * sizeof(uint32_t)) != (size_t) buf);
kenjiArai 1:9db0e321a9f4 118 chunk = std::min(current_sector_size - (addr % current_sector_size), size);
kenjiArai 1:9db0e321a9f4 119 // Need to use the internal page buffer in any of these two cases:
kenjiArai 1:9db0e321a9f4 120 // 1. Size is not page aligned
kenjiArai 1:9db0e321a9f4 121 // 2. Source buffer is not aligned to uint32_t. This is not supported by many targets (although
kenjiArai 1:9db0e321a9f4 122 // the pointer they accept is of uint8_t).
kenjiArai 1:9db0e321a9f4 123 if (unaligned_src || (chunk < page_size)) {
kenjiArai 1:9db0e321a9f4 124 chunk = std::min(chunk, page_size);
kenjiArai 1:9db0e321a9f4 125 memcpy(_page_buf, buf, chunk);
kenjiArai 1:9db0e321a9f4 126 if (chunk < page_size) {
kenjiArai 1:9db0e321a9f4 127 memset(_page_buf + chunk, flash_erase_value, page_size - chunk);
kenjiArai 1:9db0e321a9f4 128 }
kenjiArai 1:9db0e321a9f4 129 prog_buf = _page_buf;
kenjiArai 1:9db0e321a9f4 130 prog_size = page_size;
kenjiArai 1:9db0e321a9f4 131 } else {
kenjiArai 1:9db0e321a9f4 132 chunk = chunk / page_size * page_size;
kenjiArai 1:9db0e321a9f4 133 prog_buf = buf;
kenjiArai 1:9db0e321a9f4 134 prog_size = chunk;
kenjiArai 1:9db0e321a9f4 135 }
kenjiArai 1:9db0e321a9f4 136 {
kenjiArai 1:9db0e321a9f4 137 // Few boards may fail the write actions due to HW limitations (like critical drivers that
kenjiArai 1:9db0e321a9f4 138 // disable flash operations). Just retry a few times until success.
kenjiArai 1:9db0e321a9f4 139 for (unsigned int retry = 0; retry < num_write_retries; retry++) {
kenjiArai 1:9db0e321a9f4 140 ScopedRamExecutionLock make_ram_executable;
kenjiArai 1:9db0e321a9f4 141 ScopedRomWriteLock make_rom_writable;
kenjiArai 1:9db0e321a9f4 142 ret = flash_program_page(&_flash, addr, prog_buf, prog_size);
kenjiArai 1:9db0e321a9f4 143 if (ret) {
kenjiArai 1:9db0e321a9f4 144 ret = -1;
kenjiArai 1:9db0e321a9f4 145 } else {
kenjiArai 1:9db0e321a9f4 146 break;
kenjiArai 1:9db0e321a9f4 147 }
kenjiArai 1:9db0e321a9f4 148 }
kenjiArai 1:9db0e321a9f4 149 }
kenjiArai 1:9db0e321a9f4 150 size -= chunk;
kenjiArai 1:9db0e321a9f4 151 addr += chunk;
kenjiArai 1:9db0e321a9f4 152 buf += chunk;
kenjiArai 1:9db0e321a9f4 153 }
kenjiArai 1:9db0e321a9f4 154 _mutex->unlock();
kenjiArai 1:9db0e321a9f4 155
kenjiArai 1:9db0e321a9f4 156 return ret;
kenjiArai 1:9db0e321a9f4 157 }
kenjiArai 1:9db0e321a9f4 158
kenjiArai 1:9db0e321a9f4 159 bool FlashIAP::is_aligned_to_sector(uint32_t addr, uint32_t size)
kenjiArai 1:9db0e321a9f4 160 {
kenjiArai 1:9db0e321a9f4 161 uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
kenjiArai 1:9db0e321a9f4 162 if (!is_aligned(size, current_sector_size) ||
kenjiArai 1:9db0e321a9f4 163 !is_aligned(addr, current_sector_size)) {
kenjiArai 1:9db0e321a9f4 164 return false;
kenjiArai 1:9db0e321a9f4 165 } else {
kenjiArai 1:9db0e321a9f4 166 return true;
kenjiArai 1:9db0e321a9f4 167 }
kenjiArai 1:9db0e321a9f4 168 }
kenjiArai 1:9db0e321a9f4 169
kenjiArai 1:9db0e321a9f4 170 int FlashIAP::erase(uint32_t addr, uint32_t size)
kenjiArai 1:9db0e321a9f4 171 {
kenjiArai 1:9db0e321a9f4 172 uint32_t current_sector_size;
kenjiArai 1:9db0e321a9f4 173 uint32_t flash_size = flash_get_size(&_flash);
kenjiArai 1:9db0e321a9f4 174 uint32_t flash_start_addr = flash_get_start_address(&_flash);
kenjiArai 1:9db0e321a9f4 175 uint32_t flash_end_addr = flash_start_addr + flash_size;
kenjiArai 1:9db0e321a9f4 176 uint32_t erase_end_addr = addr + size;
kenjiArai 1:9db0e321a9f4 177
kenjiArai 1:9db0e321a9f4 178 if (erase_end_addr > flash_end_addr) {
kenjiArai 1:9db0e321a9f4 179 return -1;
kenjiArai 1:9db0e321a9f4 180 } else if (erase_end_addr < flash_end_addr) {
kenjiArai 1:9db0e321a9f4 181 uint32_t following_sector_size = flash_get_sector_size(&_flash, erase_end_addr);
kenjiArai 1:9db0e321a9f4 182 if (!is_aligned(erase_end_addr, following_sector_size)) {
kenjiArai 1:9db0e321a9f4 183 return -1;
kenjiArai 1:9db0e321a9f4 184 }
kenjiArai 1:9db0e321a9f4 185 }
kenjiArai 1:9db0e321a9f4 186
kenjiArai 1:9db0e321a9f4 187 int32_t ret = 0;
kenjiArai 1:9db0e321a9f4 188 _mutex->lock();
kenjiArai 1:9db0e321a9f4 189 while (size && !ret) {
kenjiArai 1:9db0e321a9f4 190 // Few boards may fail the erase actions due to HW limitations (like critical drivers that
kenjiArai 1:9db0e321a9f4 191 // disable flash operations). Just retry a few times until success.
kenjiArai 1:9db0e321a9f4 192 for (unsigned int retry = 0; retry < num_write_retries; retry++) {
kenjiArai 1:9db0e321a9f4 193 ScopedRamExecutionLock make_ram_executable;
kenjiArai 1:9db0e321a9f4 194 ScopedRomWriteLock make_rom_writable;
kenjiArai 1:9db0e321a9f4 195 ret = flash_erase_sector(&_flash, addr);
kenjiArai 1:9db0e321a9f4 196 if (ret) {
kenjiArai 1:9db0e321a9f4 197 ret = -1;
kenjiArai 1:9db0e321a9f4 198 } else {
kenjiArai 1:9db0e321a9f4 199 break;
kenjiArai 1:9db0e321a9f4 200 }
kenjiArai 1:9db0e321a9f4 201 }
kenjiArai 1:9db0e321a9f4 202 current_sector_size = flash_get_sector_size(&_flash, addr);
kenjiArai 1:9db0e321a9f4 203 size -= current_sector_size;
kenjiArai 1:9db0e321a9f4 204 addr += current_sector_size;
kenjiArai 1:9db0e321a9f4 205 }
kenjiArai 1:9db0e321a9f4 206 _mutex->unlock();
kenjiArai 1:9db0e321a9f4 207 return ret;
kenjiArai 1:9db0e321a9f4 208 }
kenjiArai 1:9db0e321a9f4 209
kenjiArai 1:9db0e321a9f4 210 uint32_t FlashIAP::get_page_size() const
kenjiArai 1:9db0e321a9f4 211 {
kenjiArai 1:9db0e321a9f4 212 return flash_get_page_size(&_flash);
kenjiArai 1:9db0e321a9f4 213 }
kenjiArai 1:9db0e321a9f4 214
kenjiArai 1:9db0e321a9f4 215 uint32_t FlashIAP::get_sector_size(uint32_t addr) const
kenjiArai 1:9db0e321a9f4 216 {
kenjiArai 1:9db0e321a9f4 217 return flash_get_sector_size(&_flash, addr);
kenjiArai 1:9db0e321a9f4 218 }
kenjiArai 1:9db0e321a9f4 219
kenjiArai 1:9db0e321a9f4 220 uint32_t FlashIAP::get_flash_start() const
kenjiArai 1:9db0e321a9f4 221 {
kenjiArai 1:9db0e321a9f4 222 return flash_get_start_address(&_flash);
kenjiArai 1:9db0e321a9f4 223 }
kenjiArai 1:9db0e321a9f4 224
kenjiArai 1:9db0e321a9f4 225 uint32_t FlashIAP::get_flash_size() const
kenjiArai 1:9db0e321a9f4 226 {
kenjiArai 1:9db0e321a9f4 227 return flash_get_size(&_flash);
kenjiArai 1:9db0e321a9f4 228 }
kenjiArai 1:9db0e321a9f4 229
kenjiArai 1:9db0e321a9f4 230 uint8_t FlashIAP::get_erase_value() const
kenjiArai 1:9db0e321a9f4 231 {
kenjiArai 1:9db0e321a9f4 232 return flash_get_erase_value(&_flash);
kenjiArai 1:9db0e321a9f4 233 }
kenjiArai 1:9db0e321a9f4 234
kenjiArai 1:9db0e321a9f4 235 }
kenjiArai 1:9db0e321a9f4 236
kenjiArai 1:9db0e321a9f4 237 #endif