takashi kadono / Mbed OS Nucleo446_SSD1331

Dependencies:   ssd1331

Committer:
kadonotakashi
Date:
Thu Oct 11 02:27:46 2018 +0000
Revision:
3:f3764f852aa8
Parent:
0:8fdf9a60065b
Nucreo 446 + SSD1331 test version;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kadonotakashi 0:8fdf9a60065b 1 /* mbed Microcontroller Library
kadonotakashi 0:8fdf9a60065b 2 * Copyright (c) 2018 ARM Limited
kadonotakashi 0:8fdf9a60065b 3 *
kadonotakashi 0:8fdf9a60065b 4 * Licensed under the Apache License, Version 2.0 (the "License");
kadonotakashi 0:8fdf9a60065b 5 * you may not use this file except in compliance with the License.
kadonotakashi 0:8fdf9a60065b 6 * You may obtain a copy of the License at
kadonotakashi 0:8fdf9a60065b 7 *
kadonotakashi 0:8fdf9a60065b 8 * http://www.apache.org/licenses/LICENSE-2.0
kadonotakashi 0:8fdf9a60065b 9 *
kadonotakashi 0:8fdf9a60065b 10 * Unless required by applicable law or agreed to in writing, software
kadonotakashi 0:8fdf9a60065b 11 * distributed under the License is distributed on an "AS IS" BASIS,
kadonotakashi 0:8fdf9a60065b 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kadonotakashi 0:8fdf9a60065b 13 * See the License for the specific language governing permissions and
kadonotakashi 0:8fdf9a60065b 14 * limitations under the License.
kadonotakashi 0:8fdf9a60065b 15 */
kadonotakashi 0:8fdf9a60065b 16
kadonotakashi 0:8fdf9a60065b 17 #include "BufferedBlockDevice.h"
kadonotakashi 0:8fdf9a60065b 18 #include "mbed_assert.h"
kadonotakashi 0:8fdf9a60065b 19 #include "mbed_critical.h"
kadonotakashi 0:8fdf9a60065b 20 #include <algorithm>
kadonotakashi 0:8fdf9a60065b 21 #include <string.h>
kadonotakashi 0:8fdf9a60065b 22
kadonotakashi 0:8fdf9a60065b 23 static inline uint32_t align_down(bd_size_t val, bd_size_t size)
kadonotakashi 0:8fdf9a60065b 24 {
kadonotakashi 0:8fdf9a60065b 25 return val / size * size;
kadonotakashi 0:8fdf9a60065b 26 }
kadonotakashi 0:8fdf9a60065b 27
kadonotakashi 0:8fdf9a60065b 28 BufferedBlockDevice::BufferedBlockDevice(BlockDevice *bd)
kadonotakashi 0:8fdf9a60065b 29 : _bd(bd), _bd_program_size(0), _curr_aligned_addr(0), _flushed(true), _cache(0), _init_ref_count(0), _is_initialized(false)
kadonotakashi 0:8fdf9a60065b 30 {
kadonotakashi 0:8fdf9a60065b 31 }
kadonotakashi 0:8fdf9a60065b 32
kadonotakashi 0:8fdf9a60065b 33 BufferedBlockDevice::~BufferedBlockDevice()
kadonotakashi 0:8fdf9a60065b 34 {
kadonotakashi 0:8fdf9a60065b 35 deinit();
kadonotakashi 0:8fdf9a60065b 36 }
kadonotakashi 0:8fdf9a60065b 37
kadonotakashi 0:8fdf9a60065b 38 int BufferedBlockDevice::init()
kadonotakashi 0:8fdf9a60065b 39 {
kadonotakashi 0:8fdf9a60065b 40 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
kadonotakashi 0:8fdf9a60065b 41
kadonotakashi 0:8fdf9a60065b 42 if (val != 1) {
kadonotakashi 0:8fdf9a60065b 43 return BD_ERROR_OK;
kadonotakashi 0:8fdf9a60065b 44 }
kadonotakashi 0:8fdf9a60065b 45
kadonotakashi 0:8fdf9a60065b 46 int err = _bd->init();
kadonotakashi 0:8fdf9a60065b 47 if (err) {
kadonotakashi 0:8fdf9a60065b 48 return err;
kadonotakashi 0:8fdf9a60065b 49 }
kadonotakashi 0:8fdf9a60065b 50
kadonotakashi 0:8fdf9a60065b 51 _bd_program_size = _bd->get_program_size();
kadonotakashi 0:8fdf9a60065b 52
kadonotakashi 0:8fdf9a60065b 53 if (!_cache) {
kadonotakashi 0:8fdf9a60065b 54 _cache = new uint8_t[_bd_program_size];
kadonotakashi 0:8fdf9a60065b 55 }
kadonotakashi 0:8fdf9a60065b 56
kadonotakashi 0:8fdf9a60065b 57 _curr_aligned_addr = _bd->size();
kadonotakashi 0:8fdf9a60065b 58 _flushed = true;
kadonotakashi 0:8fdf9a60065b 59
kadonotakashi 0:8fdf9a60065b 60 _is_initialized = true;
kadonotakashi 0:8fdf9a60065b 61 return BD_ERROR_OK;
kadonotakashi 0:8fdf9a60065b 62 }
kadonotakashi 0:8fdf9a60065b 63
kadonotakashi 0:8fdf9a60065b 64 int BufferedBlockDevice::deinit()
kadonotakashi 0:8fdf9a60065b 65 {
kadonotakashi 0:8fdf9a60065b 66 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 67 return BD_ERROR_OK;
kadonotakashi 0:8fdf9a60065b 68 }
kadonotakashi 0:8fdf9a60065b 69
kadonotakashi 0:8fdf9a60065b 70 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);
kadonotakashi 0:8fdf9a60065b 71
kadonotakashi 0:8fdf9a60065b 72 if (val) {
kadonotakashi 0:8fdf9a60065b 73 return BD_ERROR_OK;
kadonotakashi 0:8fdf9a60065b 74 }
kadonotakashi 0:8fdf9a60065b 75
kadonotakashi 0:8fdf9a60065b 76 delete[] _cache;
kadonotakashi 0:8fdf9a60065b 77 _cache = 0;
kadonotakashi 0:8fdf9a60065b 78 _is_initialized = false;
kadonotakashi 0:8fdf9a60065b 79 return _bd->deinit();
kadonotakashi 0:8fdf9a60065b 80 }
kadonotakashi 0:8fdf9a60065b 81
kadonotakashi 0:8fdf9a60065b 82 int BufferedBlockDevice::flush()
kadonotakashi 0:8fdf9a60065b 83 {
kadonotakashi 0:8fdf9a60065b 84 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 85 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 86 }
kadonotakashi 0:8fdf9a60065b 87
kadonotakashi 0:8fdf9a60065b 88 if (!_flushed) {
kadonotakashi 0:8fdf9a60065b 89 int ret = _bd->program(_cache, _curr_aligned_addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 90 if (ret) {
kadonotakashi 0:8fdf9a60065b 91 return ret;
kadonotakashi 0:8fdf9a60065b 92 }
kadonotakashi 0:8fdf9a60065b 93 _flushed = true;
kadonotakashi 0:8fdf9a60065b 94 }
kadonotakashi 0:8fdf9a60065b 95 return 0;
kadonotakashi 0:8fdf9a60065b 96 }
kadonotakashi 0:8fdf9a60065b 97
kadonotakashi 0:8fdf9a60065b 98 int BufferedBlockDevice::sync()
kadonotakashi 0:8fdf9a60065b 99 {
kadonotakashi 0:8fdf9a60065b 100 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 101 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 102 }
kadonotakashi 0:8fdf9a60065b 103
kadonotakashi 0:8fdf9a60065b 104 int ret = flush();
kadonotakashi 0:8fdf9a60065b 105 if (ret) {
kadonotakashi 0:8fdf9a60065b 106 return ret;
kadonotakashi 0:8fdf9a60065b 107 }
kadonotakashi 0:8fdf9a60065b 108 return _bd->sync();
kadonotakashi 0:8fdf9a60065b 109 }
kadonotakashi 0:8fdf9a60065b 110
kadonotakashi 0:8fdf9a60065b 111 int BufferedBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size)
kadonotakashi 0:8fdf9a60065b 112 {
kadonotakashi 0:8fdf9a60065b 113 MBED_ASSERT(_cache);
kadonotakashi 0:8fdf9a60065b 114 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 115 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 116 }
kadonotakashi 0:8fdf9a60065b 117
kadonotakashi 0:8fdf9a60065b 118 bool moved_unit = false;
kadonotakashi 0:8fdf9a60065b 119
kadonotakashi 0:8fdf9a60065b 120 bd_addr_t aligned_addr = align_down(addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 121
kadonotakashi 0:8fdf9a60065b 122 uint8_t *buf = static_cast<uint8_t *> (b);
kadonotakashi 0:8fdf9a60065b 123
kadonotakashi 0:8fdf9a60065b 124 if (aligned_addr != _curr_aligned_addr) {
kadonotakashi 0:8fdf9a60065b 125 // Need to flush if moved to another program unit
kadonotakashi 0:8fdf9a60065b 126 flush();
kadonotakashi 0:8fdf9a60065b 127 _curr_aligned_addr = aligned_addr;
kadonotakashi 0:8fdf9a60065b 128 moved_unit = true;
kadonotakashi 0:8fdf9a60065b 129 }
kadonotakashi 0:8fdf9a60065b 130
kadonotakashi 0:8fdf9a60065b 131 while (size) {
kadonotakashi 0:8fdf9a60065b 132 _curr_aligned_addr = align_down(addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 133 if (moved_unit) {
kadonotakashi 0:8fdf9a60065b 134 int ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 135 if (ret) {
kadonotakashi 0:8fdf9a60065b 136 return ret;
kadonotakashi 0:8fdf9a60065b 137 }
kadonotakashi 0:8fdf9a60065b 138 }
kadonotakashi 0:8fdf9a60065b 139 bd_addr_t offs_in_buf = addr - _curr_aligned_addr;
kadonotakashi 0:8fdf9a60065b 140 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size);
kadonotakashi 0:8fdf9a60065b 141 memcpy(buf, _cache + offs_in_buf, chunk);
kadonotakashi 0:8fdf9a60065b 142 moved_unit = true;
kadonotakashi 0:8fdf9a60065b 143 buf += chunk;
kadonotakashi 0:8fdf9a60065b 144 addr += chunk;
kadonotakashi 0:8fdf9a60065b 145 size -= chunk;
kadonotakashi 0:8fdf9a60065b 146 }
kadonotakashi 0:8fdf9a60065b 147
kadonotakashi 0:8fdf9a60065b 148 return 0;
kadonotakashi 0:8fdf9a60065b 149 }
kadonotakashi 0:8fdf9a60065b 150
kadonotakashi 0:8fdf9a60065b 151 int BufferedBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size)
kadonotakashi 0:8fdf9a60065b 152 {
kadonotakashi 0:8fdf9a60065b 153 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 154 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 155 }
kadonotakashi 0:8fdf9a60065b 156
kadonotakashi 0:8fdf9a60065b 157 int ret;
kadonotakashi 0:8fdf9a60065b 158 bool moved_unit = false;
kadonotakashi 0:8fdf9a60065b 159
kadonotakashi 0:8fdf9a60065b 160 bd_addr_t aligned_addr = align_down(addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 161
kadonotakashi 0:8fdf9a60065b 162 const uint8_t *buf = static_cast <const uint8_t *> (b);
kadonotakashi 0:8fdf9a60065b 163
kadonotakashi 0:8fdf9a60065b 164 // Need to flush if moved to another program unit
kadonotakashi 0:8fdf9a60065b 165 if (aligned_addr != _curr_aligned_addr) {
kadonotakashi 0:8fdf9a60065b 166 flush();
kadonotakashi 0:8fdf9a60065b 167 _curr_aligned_addr = aligned_addr;
kadonotakashi 0:8fdf9a60065b 168 moved_unit = true;
kadonotakashi 0:8fdf9a60065b 169 }
kadonotakashi 0:8fdf9a60065b 170
kadonotakashi 0:8fdf9a60065b 171 while (size) {
kadonotakashi 0:8fdf9a60065b 172 _curr_aligned_addr = align_down(addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 173 bd_addr_t offs_in_buf = addr - _curr_aligned_addr;
kadonotakashi 0:8fdf9a60065b 174 bd_size_t chunk = std::min(_bd_program_size - offs_in_buf, size);
kadonotakashi 0:8fdf9a60065b 175 const uint8_t *prog_buf;
kadonotakashi 0:8fdf9a60065b 176 if (chunk < _bd_program_size) {
kadonotakashi 0:8fdf9a60065b 177 // If moved a unit, and program doesn't cover entire unit, it means we don't have the entire
kadonotakashi 0:8fdf9a60065b 178 // program unit cached - need to complete it from underlying BD
kadonotakashi 0:8fdf9a60065b 179 if (moved_unit) {
kadonotakashi 0:8fdf9a60065b 180 ret = _bd->read(_cache, _curr_aligned_addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 181 if (ret) {
kadonotakashi 0:8fdf9a60065b 182 return ret;
kadonotakashi 0:8fdf9a60065b 183 }
kadonotakashi 0:8fdf9a60065b 184 }
kadonotakashi 0:8fdf9a60065b 185 memcpy(_cache + offs_in_buf, buf, chunk);
kadonotakashi 0:8fdf9a60065b 186 prog_buf = _cache;
kadonotakashi 0:8fdf9a60065b 187 } else {
kadonotakashi 0:8fdf9a60065b 188 // No need to copy data to our cache on each iteration. Just make sure it's updated
kadonotakashi 0:8fdf9a60065b 189 // on the last iteration, when size is not greater than program size (can't be smaller, as
kadonotakashi 0:8fdf9a60065b 190 // this is covered in the previous condition).
kadonotakashi 0:8fdf9a60065b 191 prog_buf = buf;
kadonotakashi 0:8fdf9a60065b 192 if (size == _bd_program_size) {
kadonotakashi 0:8fdf9a60065b 193 memcpy(_cache, buf, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 194 }
kadonotakashi 0:8fdf9a60065b 195 }
kadonotakashi 0:8fdf9a60065b 196
kadonotakashi 0:8fdf9a60065b 197 // Don't flush on the last iteration, just on all preceding ones.
kadonotakashi 0:8fdf9a60065b 198 if (size > chunk) {
kadonotakashi 0:8fdf9a60065b 199 ret = _bd->program(prog_buf, _curr_aligned_addr, _bd_program_size);
kadonotakashi 0:8fdf9a60065b 200 if (ret) {
kadonotakashi 0:8fdf9a60065b 201 return ret;
kadonotakashi 0:8fdf9a60065b 202 }
kadonotakashi 0:8fdf9a60065b 203 _bd->sync();
kadonotakashi 0:8fdf9a60065b 204 } else {
kadonotakashi 0:8fdf9a60065b 205 _flushed = false;
kadonotakashi 0:8fdf9a60065b 206 }
kadonotakashi 0:8fdf9a60065b 207
kadonotakashi 0:8fdf9a60065b 208 moved_unit = true;
kadonotakashi 0:8fdf9a60065b 209 buf += chunk;
kadonotakashi 0:8fdf9a60065b 210 addr += chunk;
kadonotakashi 0:8fdf9a60065b 211 size -= chunk;
kadonotakashi 0:8fdf9a60065b 212 }
kadonotakashi 0:8fdf9a60065b 213
kadonotakashi 0:8fdf9a60065b 214 return 0;
kadonotakashi 0:8fdf9a60065b 215 }
kadonotakashi 0:8fdf9a60065b 216
kadonotakashi 0:8fdf9a60065b 217 int BufferedBlockDevice::erase(bd_addr_t addr, bd_size_t size)
kadonotakashi 0:8fdf9a60065b 218 {
kadonotakashi 0:8fdf9a60065b 219 MBED_ASSERT(is_valid_erase(addr, size));
kadonotakashi 0:8fdf9a60065b 220 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 221 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 222 }
kadonotakashi 0:8fdf9a60065b 223
kadonotakashi 0:8fdf9a60065b 224 return _bd->erase(addr, size);
kadonotakashi 0:8fdf9a60065b 225 }
kadonotakashi 0:8fdf9a60065b 226
kadonotakashi 0:8fdf9a60065b 227 int BufferedBlockDevice::trim(bd_addr_t addr, bd_size_t size)
kadonotakashi 0:8fdf9a60065b 228 {
kadonotakashi 0:8fdf9a60065b 229 MBED_ASSERT(is_valid_erase(addr, size));
kadonotakashi 0:8fdf9a60065b 230 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 231 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 232 }
kadonotakashi 0:8fdf9a60065b 233
kadonotakashi 0:8fdf9a60065b 234 if ((_curr_aligned_addr >= addr) && (_curr_aligned_addr <= addr + size)) {
kadonotakashi 0:8fdf9a60065b 235 _flushed = true;
kadonotakashi 0:8fdf9a60065b 236 _curr_aligned_addr = _bd->size();
kadonotakashi 0:8fdf9a60065b 237 }
kadonotakashi 0:8fdf9a60065b 238 return _bd->trim(addr, size);
kadonotakashi 0:8fdf9a60065b 239 }
kadonotakashi 0:8fdf9a60065b 240
kadonotakashi 0:8fdf9a60065b 241 bd_size_t BufferedBlockDevice::get_read_size() const
kadonotakashi 0:8fdf9a60065b 242 {
kadonotakashi 0:8fdf9a60065b 243 return 1;
kadonotakashi 0:8fdf9a60065b 244 }
kadonotakashi 0:8fdf9a60065b 245
kadonotakashi 0:8fdf9a60065b 246 bd_size_t BufferedBlockDevice::get_program_size() const
kadonotakashi 0:8fdf9a60065b 247 {
kadonotakashi 0:8fdf9a60065b 248 return 1;
kadonotakashi 0:8fdf9a60065b 249 }
kadonotakashi 0:8fdf9a60065b 250
kadonotakashi 0:8fdf9a60065b 251 bd_size_t BufferedBlockDevice::get_erase_size() const
kadonotakashi 0:8fdf9a60065b 252 {
kadonotakashi 0:8fdf9a60065b 253 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 254 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 255 }
kadonotakashi 0:8fdf9a60065b 256
kadonotakashi 0:8fdf9a60065b 257 return _bd->get_erase_size();
kadonotakashi 0:8fdf9a60065b 258 }
kadonotakashi 0:8fdf9a60065b 259
kadonotakashi 0:8fdf9a60065b 260 bd_size_t BufferedBlockDevice::get_erase_size(bd_addr_t addr) const
kadonotakashi 0:8fdf9a60065b 261 {
kadonotakashi 0:8fdf9a60065b 262 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 263 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 264 }
kadonotakashi 0:8fdf9a60065b 265
kadonotakashi 0:8fdf9a60065b 266 return _bd->get_erase_size(addr);
kadonotakashi 0:8fdf9a60065b 267 }
kadonotakashi 0:8fdf9a60065b 268
kadonotakashi 0:8fdf9a60065b 269 int BufferedBlockDevice::get_erase_value() const
kadonotakashi 0:8fdf9a60065b 270 {
kadonotakashi 0:8fdf9a60065b 271 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 272 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 273 }
kadonotakashi 0:8fdf9a60065b 274
kadonotakashi 0:8fdf9a60065b 275 return _bd->get_erase_value();
kadonotakashi 0:8fdf9a60065b 276 }
kadonotakashi 0:8fdf9a60065b 277
kadonotakashi 0:8fdf9a60065b 278 bd_size_t BufferedBlockDevice::size() const
kadonotakashi 0:8fdf9a60065b 279 {
kadonotakashi 0:8fdf9a60065b 280 if (!_is_initialized) {
kadonotakashi 0:8fdf9a60065b 281 return BD_ERROR_DEVICE_ERROR;
kadonotakashi 0:8fdf9a60065b 282 }
kadonotakashi 0:8fdf9a60065b 283
kadonotakashi 0:8fdf9a60065b 284 return _bd->size();
kadonotakashi 0:8fdf9a60065b 285 }