RTC auf true

Committer:
kevman
Date:
Wed Mar 13 11:03:24 2019 +0000
Revision:
2:7aab896b1a3b
2019-03-13

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kevman 2:7aab896b1a3b 1 /* mbed Microcontroller Library
kevman 2:7aab896b1a3b 2 * Copyright (c) 2016 ARM Limited
kevman 2:7aab896b1a3b 3 *
kevman 2:7aab896b1a3b 4 * Licensed under the Apache License, Version 2.0 (the "License");
kevman 2:7aab896b1a3b 5 * you may not use this file except in compliance with the License.
kevman 2:7aab896b1a3b 6 * You may obtain a copy of the License at
kevman 2:7aab896b1a3b 7 *
kevman 2:7aab896b1a3b 8 * http://www.apache.org/licenses/LICENSE-2.0
kevman 2:7aab896b1a3b 9 *
kevman 2:7aab896b1a3b 10 * Unless required by applicable law or agreed to in writing, software
kevman 2:7aab896b1a3b 11 * distributed under the License is distributed on an "AS IS" BASIS,
kevman 2:7aab896b1a3b 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
kevman 2:7aab896b1a3b 13 * See the License for the specific language governing permissions and
kevman 2:7aab896b1a3b 14 * limitations under the License.
kevman 2:7aab896b1a3b 15 */
kevman 2:7aab896b1a3b 16
kevman 2:7aab896b1a3b 17 #include "DataFlashBlockDevice.h"
kevman 2:7aab896b1a3b 18 #include "mbed_critical.h"
kevman 2:7aab896b1a3b 19
kevman 2:7aab896b1a3b 20 #include <inttypes.h>
kevman 2:7aab896b1a3b 21
kevman 2:7aab896b1a3b 22 /* constants */
kevman 2:7aab896b1a3b 23 #define DATAFLASH_READ_SIZE 1
kevman 2:7aab896b1a3b 24 #define DATAFLASH_PROG_SIZE 1
kevman 2:7aab896b1a3b 25 #define DATAFLASH_TIMEOUT 10000
kevman 2:7aab896b1a3b 26 #define DATAFLASH_ID_MATCH 0x1F20
kevman 2:7aab896b1a3b 27 #define DATAFLASH_ID_DENSITY_MASK 0x001F
kevman 2:7aab896b1a3b 28 #define DATAFLASH_PAGE_SIZE_256 0x0100
kevman 2:7aab896b1a3b 29 #define DATAFLASH_PAGE_SIZE_264 0x0108
kevman 2:7aab896b1a3b 30 #define DATAFLASH_PAGE_SIZE_512 0x0200
kevman 2:7aab896b1a3b 31 #define DATAFLASH_PAGE_SIZE_528 0x0210
kevman 2:7aab896b1a3b 32 #define DATAFLASH_BLOCK_SIZE_2K 0x0800
kevman 2:7aab896b1a3b 33 #define DATAFLASH_BLOCK_SIZE_2K1 0x0840
kevman 2:7aab896b1a3b 34 #define DATAFLASH_BLOCK_SIZE_4K 0x1000
kevman 2:7aab896b1a3b 35 #define DATAFLASH_BLOCK_SIZE_4K1 0x1080
kevman 2:7aab896b1a3b 36 #define DATAFLASH_PAGE_BIT_264 9
kevman 2:7aab896b1a3b 37 #define DATAFLASH_PAGE_BIT_528 10
kevman 2:7aab896b1a3b 38
kevman 2:7aab896b1a3b 39 /* enable debug */
kevman 2:7aab896b1a3b 40 #ifndef DATAFLASH_DEBUG
kevman 2:7aab896b1a3b 41 #define DATAFLASH_DEBUG 0
kevman 2:7aab896b1a3b 42 #endif /* DATAFLASH_DEBUG */
kevman 2:7aab896b1a3b 43
kevman 2:7aab896b1a3b 44 #if DATAFLASH_DEBUG
kevman 2:7aab896b1a3b 45 #define DEBUG_PRINTF(...) printf(__VA_ARGS__)
kevman 2:7aab896b1a3b 46 #else
kevman 2:7aab896b1a3b 47 #define DEBUG_PRINTF(...)
kevman 2:7aab896b1a3b 48 #endif
kevman 2:7aab896b1a3b 49
kevman 2:7aab896b1a3b 50 void _print_status(uint16_t status);
kevman 2:7aab896b1a3b 51
kevman 2:7aab896b1a3b 52 /* non-exhaustive opcode list */
kevman 2:7aab896b1a3b 53 enum opcode {
kevman 2:7aab896b1a3b 54 DATAFLASH_OP_NOP = 0x00,
kevman 2:7aab896b1a3b 55 DATAFLASH_OP_STATUS = 0xD7,
kevman 2:7aab896b1a3b 56 DATAFLASH_OP_ID = 0x9F,
kevman 2:7aab896b1a3b 57 DATAFLASH_OP_READ_LOW_POWER = 0x01,
kevman 2:7aab896b1a3b 58 DATAFLASH_OP_READ_LOW_FREQUENCY = 0x03,
kevman 2:7aab896b1a3b 59 DATAFLASH_OP_PROGRAM_DIRECT = 0x02, // Program through Buffer 1 without Built-In Erase
kevman 2:7aab896b1a3b 60 DATAFLASH_OP_PROGRAM_DIRECT_WITH_ERASE = 0x82,
kevman 2:7aab896b1a3b 61 DATAFLASH_OP_ERASE_BLOCK = 0x50,
kevman 2:7aab896b1a3b 62 };
kevman 2:7aab896b1a3b 63
kevman 2:7aab896b1a3b 64 /* non-exhaustive command list */
kevman 2:7aab896b1a3b 65 enum command {
kevman 2:7aab896b1a3b 66 DATAFLASH_COMMAND_WRITE_DISABLE = 0x3D2A7FA9,
kevman 2:7aab896b1a3b 67 DATAFLASH_COMMAND_WRITE_ENABLE = 0x3D2A7F9A,
kevman 2:7aab896b1a3b 68 DATAFLASH_COMMAND_BINARY_PAGE_SIZE = 0x3D2A80A6,
kevman 2:7aab896b1a3b 69 DATAFLASH_COMMAND_DATAFLASH_PAGE_SIZE = 0x3D2A80A7,
kevman 2:7aab896b1a3b 70 };
kevman 2:7aab896b1a3b 71
kevman 2:7aab896b1a3b 72 /* bit masks for interpreting the status register */
kevman 2:7aab896b1a3b 73 enum status_bit {
kevman 2:7aab896b1a3b 74 DATAFLASH_BIT_READY = (0x01 << 15),
kevman 2:7aab896b1a3b 75 DATAFLASH_BIT_COMPARE = (0x01 << 14),
kevman 2:7aab896b1a3b 76 DATAFLASH_BIT_DENSITY = (0x0F << 10),
kevman 2:7aab896b1a3b 77 DATAFLASH_BIT_PROTECT = (0x01 << 9),
kevman 2:7aab896b1a3b 78 DATAFLASH_BIT_PAGE_SIZE = (0x01 << 8),
kevman 2:7aab896b1a3b 79
kevman 2:7aab896b1a3b 80 DATAFLASH_BIT_ERASE_PROGRAM_ERROR = (0x01 << 5),
kevman 2:7aab896b1a3b 81 DATAFLASH_BIT_SECTOR_LOCKDOWN = (0x01 << 3),
kevman 2:7aab896b1a3b 82 DATAFLASH_BIT_PROGRAM_SUSPEND_2 = (0x01 << 2),
kevman 2:7aab896b1a3b 83 DATAFLASH_BIT_PROGRAM_SUSPEND_1 = (0x01 << 1),
kevman 2:7aab896b1a3b 84 DATAFLASH_BIT_ERASE_SUSPEND = (0x01 << 0),
kevman 2:7aab896b1a3b 85 };
kevman 2:7aab896b1a3b 86
kevman 2:7aab896b1a3b 87 /* bit masks for detecting density from status register */
kevman 2:7aab896b1a3b 88 enum status_density {
kevman 2:7aab896b1a3b 89 DATAFLASH_STATUS_DENSITY_2_MBIT = (0x05 << 10),
kevman 2:7aab896b1a3b 90 DATAFLASH_STATUS_DENSITY_4_MBIT = (0x07 << 10),
kevman 2:7aab896b1a3b 91 DATAFLASH_STATUS_DENSITY_8_MBIT = (0x09 << 10),
kevman 2:7aab896b1a3b 92 DATAFLASH_STATUS_DENSITY_16_MBIT = (0x0B << 10),
kevman 2:7aab896b1a3b 93 DATAFLASH_STATUS_DENSITY_32_MBIT = (0x0D << 10),
kevman 2:7aab896b1a3b 94 DATAFLASH_STATUS_DENSITY_64_MBIT = (0x0F << 10),
kevman 2:7aab896b1a3b 95 };
kevman 2:7aab896b1a3b 96
kevman 2:7aab896b1a3b 97 /* code for calculating density */
kevman 2:7aab896b1a3b 98 enum id_density {
kevman 2:7aab896b1a3b 99 DATAFLASH_ID_DENSITY_2_MBIT = 0x03,
kevman 2:7aab896b1a3b 100 DATAFLASH_ID_DENSITY_4_MBIT = 0x04,
kevman 2:7aab896b1a3b 101 DATAFLASH_ID_DENSITY_8_MBIT = 0x05,
kevman 2:7aab896b1a3b 102 DATAFLASH_ID_DENSITY_16_MBIT = 0x06,
kevman 2:7aab896b1a3b 103 DATAFLASH_ID_DENSITY_32_MBIT = 0x07,
kevman 2:7aab896b1a3b 104 DATAFLASH_ID_DENSITY_64_MBIT = 0x08,
kevman 2:7aab896b1a3b 105 };
kevman 2:7aab896b1a3b 106
kevman 2:7aab896b1a3b 107 /* typical duration in milliseconds for each operation */
kevman 2:7aab896b1a3b 108 enum timing {
kevman 2:7aab896b1a3b 109 DATAFLASH_TIMING_ERASE_PROGRAM_PAGE = 17,
kevman 2:7aab896b1a3b 110 DATAFLASH_TIMING_PROGRAM_PAGE = 3,
kevman 2:7aab896b1a3b 111 DATAFLASH_TIMING_ERASE_PAGE = 12,
kevman 2:7aab896b1a3b 112 DATAFLASH_TIMING_ERASE_BLOCK = 45,
kevman 2:7aab896b1a3b 113 DATAFLASH_TIMING_ERASE_SECTOR = 700,
kevman 2:7aab896b1a3b 114 DATAFLASH_TIMING_ERASE_CHIP = 45000
kevman 2:7aab896b1a3b 115 };
kevman 2:7aab896b1a3b 116
kevman 2:7aab896b1a3b 117 /* frequency domains */
kevman 2:7aab896b1a3b 118 enum frequency {
kevman 2:7aab896b1a3b 119 DATAFLASH_LOW_POWER_FREQUENCY = 15000000,
kevman 2:7aab896b1a3b 120 DATAFLASH_LOW_FREQUENCY = 50000000,
kevman 2:7aab896b1a3b 121 DATAFLASH_HIGH_FREQUENCY = 85000000,
kevman 2:7aab896b1a3b 122 DATAFLASH_HIGHEST_FREQUENCY = 104000000
kevman 2:7aab896b1a3b 123 };
kevman 2:7aab896b1a3b 124
kevman 2:7aab896b1a3b 125 /* number of dummy bytes required in each frequency domain */
kevman 2:7aab896b1a3b 126 enum dummy {
kevman 2:7aab896b1a3b 127 DATAFLASH_LOW_POWER_BYTES = 0,
kevman 2:7aab896b1a3b 128 DATAFLASH_LOW_FREQUENCY_BYTES = 0,
kevman 2:7aab896b1a3b 129 DATAFLASH_HIGH_FREQUENCY_BYTES = 1,
kevman 2:7aab896b1a3b 130 DATAFLASH_HIGHEST_FREQUENCY_BYTES = 2
kevman 2:7aab896b1a3b 131 };
kevman 2:7aab896b1a3b 132
kevman 2:7aab896b1a3b 133 DataFlashBlockDevice::DataFlashBlockDevice(PinName mosi,
kevman 2:7aab896b1a3b 134 PinName miso,
kevman 2:7aab896b1a3b 135 PinName sclk,
kevman 2:7aab896b1a3b 136 PinName cs,
kevman 2:7aab896b1a3b 137 int freq,
kevman 2:7aab896b1a3b 138 PinName nwp)
kevman 2:7aab896b1a3b 139 : _spi(mosi, miso, sclk),
kevman 2:7aab896b1a3b 140 _cs(cs, 1),
kevman 2:7aab896b1a3b 141 _nwp(nwp),
kevman 2:7aab896b1a3b 142 _device_size(0),
kevman 2:7aab896b1a3b 143 _page_size(0),
kevman 2:7aab896b1a3b 144 _block_size(0),
kevman 2:7aab896b1a3b 145 _is_initialized(0),
kevman 2:7aab896b1a3b 146 _init_ref_count(0)
kevman 2:7aab896b1a3b 147 {
kevman 2:7aab896b1a3b 148 /* check that frequency is within range */
kevman 2:7aab896b1a3b 149 if (freq > DATAFLASH_LOW_FREQUENCY) {
kevman 2:7aab896b1a3b 150
kevman 2:7aab896b1a3b 151 /* cap frequency at the highest supported one */
kevman 2:7aab896b1a3b 152 _spi.frequency(DATAFLASH_LOW_FREQUENCY);
kevman 2:7aab896b1a3b 153
kevman 2:7aab896b1a3b 154 } else {
kevman 2:7aab896b1a3b 155 /* freqency is valid, use as-is */
kevman 2:7aab896b1a3b 156 _spi.frequency(freq);
kevman 2:7aab896b1a3b 157 }
kevman 2:7aab896b1a3b 158
kevman 2:7aab896b1a3b 159 /* write protect chip if pin is connected */
kevman 2:7aab896b1a3b 160 if (nwp != NC) {
kevman 2:7aab896b1a3b 161 _nwp = 0;
kevman 2:7aab896b1a3b 162 }
kevman 2:7aab896b1a3b 163 }
kevman 2:7aab896b1a3b 164
kevman 2:7aab896b1a3b 165 int DataFlashBlockDevice::init()
kevman 2:7aab896b1a3b 166 {
kevman 2:7aab896b1a3b 167 _mutex.lock();
kevman 2:7aab896b1a3b 168 DEBUG_PRINTF("init\r\n");
kevman 2:7aab896b1a3b 169
kevman 2:7aab896b1a3b 170 if (!_is_initialized) {
kevman 2:7aab896b1a3b 171 _init_ref_count = 0;
kevman 2:7aab896b1a3b 172 }
kevman 2:7aab896b1a3b 173
kevman 2:7aab896b1a3b 174 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1);
kevman 2:7aab896b1a3b 175
kevman 2:7aab896b1a3b 176 if (val != 1) {
kevman 2:7aab896b1a3b 177 _mutex.unlock();
kevman 2:7aab896b1a3b 178 return BD_ERROR_OK;
kevman 2:7aab896b1a3b 179 }
kevman 2:7aab896b1a3b 180
kevman 2:7aab896b1a3b 181 int result = BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 182
kevman 2:7aab896b1a3b 183 /* read ID register to validate model and set dimensions */
kevman 2:7aab896b1a3b 184 uint16_t id = _get_register(DATAFLASH_OP_ID);
kevman 2:7aab896b1a3b 185
kevman 2:7aab896b1a3b 186 DEBUG_PRINTF("id: %04X\r\n", id & DATAFLASH_ID_MATCH);
kevman 2:7aab896b1a3b 187
kevman 2:7aab896b1a3b 188 /* get status register to verify the page size mode */
kevman 2:7aab896b1a3b 189 uint16_t status = _get_register(DATAFLASH_OP_STATUS);
kevman 2:7aab896b1a3b 190
kevman 2:7aab896b1a3b 191 /* manufacture ID match */
kevman 2:7aab896b1a3b 192 if ((id & DATAFLASH_ID_MATCH) == DATAFLASH_ID_MATCH) {
kevman 2:7aab896b1a3b 193
kevman 2:7aab896b1a3b 194 /* calculate density */
kevman 2:7aab896b1a3b 195 _device_size = 0x8000 << (id & DATAFLASH_ID_DENSITY_MASK);
kevman 2:7aab896b1a3b 196
kevman 2:7aab896b1a3b 197 bool binary_page_size = true;
kevman 2:7aab896b1a3b 198
kevman 2:7aab896b1a3b 199 /* check if device is configured for binary page sizes */
kevman 2:7aab896b1a3b 200 if ((status & DATAFLASH_BIT_PAGE_SIZE) == DATAFLASH_BIT_PAGE_SIZE) {
kevman 2:7aab896b1a3b 201 DEBUG_PRINTF("Page size is binary\r\n");
kevman 2:7aab896b1a3b 202
kevman 2:7aab896b1a3b 203 #if MBED_CONF_DATAFLASH_DATAFLASH_SIZE
kevman 2:7aab896b1a3b 204 /* send reconfiguration command */
kevman 2:7aab896b1a3b 205 _write_command(DATAFLASH_COMMAND_DATAFLASH_PAGE_SIZE, NULL, 0);
kevman 2:7aab896b1a3b 206
kevman 2:7aab896b1a3b 207 /* wait for device to be ready and update return code */
kevman 2:7aab896b1a3b 208 result = _sync();
kevman 2:7aab896b1a3b 209
kevman 2:7aab896b1a3b 210 /* set binary flag */
kevman 2:7aab896b1a3b 211 binary_page_size = false;
kevman 2:7aab896b1a3b 212 #else
kevman 2:7aab896b1a3b 213 /* set binary flag */
kevman 2:7aab896b1a3b 214 binary_page_size = true;
kevman 2:7aab896b1a3b 215 #endif
kevman 2:7aab896b1a3b 216 } else {
kevman 2:7aab896b1a3b 217 DEBUG_PRINTF("Page size is not binary\r\n");
kevman 2:7aab896b1a3b 218
kevman 2:7aab896b1a3b 219 #if MBED_CONF_DATAFLASH_BINARY_SIZE
kevman 2:7aab896b1a3b 220 /* send reconfiguration command */
kevman 2:7aab896b1a3b 221 _write_command(DATAFLASH_COMMAND_BINARY_PAGE_SIZE, NULL, 0);
kevman 2:7aab896b1a3b 222
kevman 2:7aab896b1a3b 223 /* wait for device to be ready and update return code */
kevman 2:7aab896b1a3b 224 result = _sync();
kevman 2:7aab896b1a3b 225
kevman 2:7aab896b1a3b 226 /* set binary flag */
kevman 2:7aab896b1a3b 227 binary_page_size = true;
kevman 2:7aab896b1a3b 228 #else
kevman 2:7aab896b1a3b 229 /* set binary flag */
kevman 2:7aab896b1a3b 230 binary_page_size = false;
kevman 2:7aab896b1a3b 231 #endif
kevman 2:7aab896b1a3b 232 }
kevman 2:7aab896b1a3b 233
kevman 2:7aab896b1a3b 234 /* set page program size and block erase size */
kevman 2:7aab896b1a3b 235 switch (id & DATAFLASH_ID_DENSITY_MASK) {
kevman 2:7aab896b1a3b 236 case DATAFLASH_ID_DENSITY_2_MBIT:
kevman 2:7aab896b1a3b 237 case DATAFLASH_ID_DENSITY_4_MBIT:
kevman 2:7aab896b1a3b 238 case DATAFLASH_ID_DENSITY_8_MBIT:
kevman 2:7aab896b1a3b 239 case DATAFLASH_ID_DENSITY_64_MBIT:
kevman 2:7aab896b1a3b 240 if (binary_page_size) {
kevman 2:7aab896b1a3b 241 _page_size = DATAFLASH_PAGE_SIZE_256;
kevman 2:7aab896b1a3b 242 _block_size = DATAFLASH_BLOCK_SIZE_2K;
kevman 2:7aab896b1a3b 243 } else {
kevman 2:7aab896b1a3b 244 _page_size = DATAFLASH_PAGE_SIZE_264;
kevman 2:7aab896b1a3b 245 _block_size = DATAFLASH_BLOCK_SIZE_2K1;
kevman 2:7aab896b1a3b 246
kevman 2:7aab896b1a3b 247 /* adjust device size */
kevman 2:7aab896b1a3b 248 _device_size = (_device_size / DATAFLASH_PAGE_SIZE_256) *
kevman 2:7aab896b1a3b 249 DATAFLASH_PAGE_SIZE_264;
kevman 2:7aab896b1a3b 250 }
kevman 2:7aab896b1a3b 251 break;
kevman 2:7aab896b1a3b 252 case DATAFLASH_ID_DENSITY_16_MBIT:
kevman 2:7aab896b1a3b 253 case DATAFLASH_ID_DENSITY_32_MBIT:
kevman 2:7aab896b1a3b 254 if (binary_page_size) {
kevman 2:7aab896b1a3b 255 _page_size = DATAFLASH_PAGE_SIZE_512;
kevman 2:7aab896b1a3b 256 _block_size = DATAFLASH_BLOCK_SIZE_4K;
kevman 2:7aab896b1a3b 257 } else {
kevman 2:7aab896b1a3b 258 _page_size = DATAFLASH_PAGE_SIZE_528;
kevman 2:7aab896b1a3b 259 _block_size = DATAFLASH_BLOCK_SIZE_4K1;
kevman 2:7aab896b1a3b 260
kevman 2:7aab896b1a3b 261 /* adjust device size */
kevman 2:7aab896b1a3b 262 _device_size = (_device_size / DATAFLASH_PAGE_SIZE_512) *
kevman 2:7aab896b1a3b 263 DATAFLASH_PAGE_SIZE_528;
kevman 2:7aab896b1a3b 264 }
kevman 2:7aab896b1a3b 265 break;
kevman 2:7aab896b1a3b 266 default:
kevman 2:7aab896b1a3b 267 break;
kevman 2:7aab896b1a3b 268 }
kevman 2:7aab896b1a3b 269
kevman 2:7aab896b1a3b 270 DEBUG_PRINTF("density: %" PRIu16 "\r\n", id & DATAFLASH_ID_DENSITY_MASK);
kevman 2:7aab896b1a3b 271 DEBUG_PRINTF("size: %" PRIu32 "\r\n", _device_size);
kevman 2:7aab896b1a3b 272 DEBUG_PRINTF("page: %" PRIu16 "\r\n", _page_size);
kevman 2:7aab896b1a3b 273 DEBUG_PRINTF("block: %" PRIu16 "\r\n", _block_size);
kevman 2:7aab896b1a3b 274
kevman 2:7aab896b1a3b 275 /* device successfully detected, set OK error code */
kevman 2:7aab896b1a3b 276 result = BD_ERROR_OK;
kevman 2:7aab896b1a3b 277 }
kevman 2:7aab896b1a3b 278
kevman 2:7aab896b1a3b 279 /* write protect device when idle */
kevman 2:7aab896b1a3b 280 _write_enable(false);
kevman 2:7aab896b1a3b 281
kevman 2:7aab896b1a3b 282 if (result == BD_ERROR_OK) {
kevman 2:7aab896b1a3b 283 _is_initialized = true;
kevman 2:7aab896b1a3b 284 }
kevman 2:7aab896b1a3b 285
kevman 2:7aab896b1a3b 286 _mutex.unlock();
kevman 2:7aab896b1a3b 287 return result;
kevman 2:7aab896b1a3b 288 }
kevman 2:7aab896b1a3b 289
kevman 2:7aab896b1a3b 290 int DataFlashBlockDevice::deinit()
kevman 2:7aab896b1a3b 291 {
kevman 2:7aab896b1a3b 292 _mutex.lock();
kevman 2:7aab896b1a3b 293 DEBUG_PRINTF("deinit\r\n");
kevman 2:7aab896b1a3b 294
kevman 2:7aab896b1a3b 295 if (!_is_initialized) {
kevman 2:7aab896b1a3b 296 _init_ref_count = 0;
kevman 2:7aab896b1a3b 297 _mutex.unlock();
kevman 2:7aab896b1a3b 298 return BD_ERROR_OK;
kevman 2:7aab896b1a3b 299 }
kevman 2:7aab896b1a3b 300
kevman 2:7aab896b1a3b 301 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1);
kevman 2:7aab896b1a3b 302
kevman 2:7aab896b1a3b 303 if (val) {
kevman 2:7aab896b1a3b 304 _mutex.unlock();
kevman 2:7aab896b1a3b 305 return BD_ERROR_OK;
kevman 2:7aab896b1a3b 306 }
kevman 2:7aab896b1a3b 307
kevman 2:7aab896b1a3b 308 _is_initialized = false;
kevman 2:7aab896b1a3b 309 _mutex.unlock();
kevman 2:7aab896b1a3b 310 return BD_ERROR_OK;
kevman 2:7aab896b1a3b 311 }
kevman 2:7aab896b1a3b 312
kevman 2:7aab896b1a3b 313 int DataFlashBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 314 {
kevman 2:7aab896b1a3b 315 _mutex.lock();
kevman 2:7aab896b1a3b 316 DEBUG_PRINTF("read: %p %" PRIX64 " %" PRIX64 "\r\n", buffer, addr, size);
kevman 2:7aab896b1a3b 317
kevman 2:7aab896b1a3b 318 if (!_is_initialized) {
kevman 2:7aab896b1a3b 319 _mutex.unlock();
kevman 2:7aab896b1a3b 320 return BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 321 }
kevman 2:7aab896b1a3b 322
kevman 2:7aab896b1a3b 323 int result = BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 324
kevman 2:7aab896b1a3b 325 /* check parameters are valid and the read is within bounds */
kevman 2:7aab896b1a3b 326 if (is_valid_read(addr, size) && buffer) {
kevman 2:7aab896b1a3b 327
kevman 2:7aab896b1a3b 328 uint8_t *external_buffer = static_cast<uint8_t *>(buffer);
kevman 2:7aab896b1a3b 329
kevman 2:7aab896b1a3b 330 /* activate device */
kevman 2:7aab896b1a3b 331 _cs = 0;
kevman 2:7aab896b1a3b 332
kevman 2:7aab896b1a3b 333 /* send read opcode */
kevman 2:7aab896b1a3b 334 _spi.write(DATAFLASH_OP_READ_LOW_FREQUENCY);
kevman 2:7aab896b1a3b 335
kevman 2:7aab896b1a3b 336 /* translate address */
kevman 2:7aab896b1a3b 337 uint32_t address = _translate_address(addr);
kevman 2:7aab896b1a3b 338
kevman 2:7aab896b1a3b 339 DEBUG_PRINTF("address: %" PRIX32 "\r\n", address);
kevman 2:7aab896b1a3b 340
kevman 2:7aab896b1a3b 341 /* send read address */
kevman 2:7aab896b1a3b 342 _spi.write((address >> 16) & 0xFF);
kevman 2:7aab896b1a3b 343 _spi.write((address >> 8) & 0xFF);
kevman 2:7aab896b1a3b 344 _spi.write(address & 0xFF);
kevman 2:7aab896b1a3b 345
kevman 2:7aab896b1a3b 346 /* clock out one byte at a time and store in external buffer */
kevman 2:7aab896b1a3b 347 for (uint32_t index = 0; index < size; index++) {
kevman 2:7aab896b1a3b 348 external_buffer[index] = _spi.write(DATAFLASH_OP_NOP);
kevman 2:7aab896b1a3b 349 }
kevman 2:7aab896b1a3b 350
kevman 2:7aab896b1a3b 351 /* deactivate device */
kevman 2:7aab896b1a3b 352 _cs = 1;
kevman 2:7aab896b1a3b 353
kevman 2:7aab896b1a3b 354 result = BD_ERROR_OK;
kevman 2:7aab896b1a3b 355 }
kevman 2:7aab896b1a3b 356
kevman 2:7aab896b1a3b 357 _mutex.unlock();
kevman 2:7aab896b1a3b 358 return result;
kevman 2:7aab896b1a3b 359 }
kevman 2:7aab896b1a3b 360
kevman 2:7aab896b1a3b 361 int DataFlashBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 362 {
kevman 2:7aab896b1a3b 363 _mutex.lock();
kevman 2:7aab896b1a3b 364 DEBUG_PRINTF("program: %p %" PRIX64 " %" PRIX64 "\r\n", buffer, addr, size);
kevman 2:7aab896b1a3b 365
kevman 2:7aab896b1a3b 366 if (!_is_initialized) {
kevman 2:7aab896b1a3b 367 _mutex.unlock();
kevman 2:7aab896b1a3b 368 return BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 369 }
kevman 2:7aab896b1a3b 370
kevman 2:7aab896b1a3b 371 int result = BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 372
kevman 2:7aab896b1a3b 373 /* check parameters are valid and the write is within bounds */
kevman 2:7aab896b1a3b 374 if (is_valid_program(addr, size) && buffer) {
kevman 2:7aab896b1a3b 375
kevman 2:7aab896b1a3b 376 const uint8_t *external_buffer = static_cast<const uint8_t *>(buffer);
kevman 2:7aab896b1a3b 377
kevman 2:7aab896b1a3b 378 /* Each write command can only cover one page at a time.
kevman 2:7aab896b1a3b 379 Find page and current page offset for handling unaligned writes.
kevman 2:7aab896b1a3b 380 */
kevman 2:7aab896b1a3b 381 uint32_t page_number = addr / _page_size;
kevman 2:7aab896b1a3b 382 uint32_t page_offset = addr % _page_size;
kevman 2:7aab896b1a3b 383
kevman 2:7aab896b1a3b 384 /* disable write protection */
kevman 2:7aab896b1a3b 385 _write_enable(true);
kevman 2:7aab896b1a3b 386
kevman 2:7aab896b1a3b 387 /* continue until all bytes have been written */
kevman 2:7aab896b1a3b 388 uint32_t bytes_written = 0;
kevman 2:7aab896b1a3b 389 while (bytes_written < size) {
kevman 2:7aab896b1a3b 390
kevman 2:7aab896b1a3b 391 /* find remaining bytes to be written */
kevman 2:7aab896b1a3b 392 uint32_t bytes_remaining = size - bytes_written;
kevman 2:7aab896b1a3b 393
kevman 2:7aab896b1a3b 394 /* cap the value at the page size and offset */
kevman 2:7aab896b1a3b 395 if (bytes_remaining > (_page_size - page_offset)) {
kevman 2:7aab896b1a3b 396 bytes_remaining = _page_size - page_offset;
kevman 2:7aab896b1a3b 397 }
kevman 2:7aab896b1a3b 398
kevman 2:7aab896b1a3b 399 /* Write one page, bytes_written keeps track of the progress,
kevman 2:7aab896b1a3b 400 page_number is the page address, and page_offset is non-zero for
kevman 2:7aab896b1a3b 401 unaligned writes.
kevman 2:7aab896b1a3b 402 */
kevman 2:7aab896b1a3b 403 result = _write_page(&external_buffer[bytes_written],
kevman 2:7aab896b1a3b 404 page_number,
kevman 2:7aab896b1a3b 405 page_offset,
kevman 2:7aab896b1a3b 406 bytes_remaining);
kevman 2:7aab896b1a3b 407
kevman 2:7aab896b1a3b 408 /* update loop variables upon success otherwise break loop */
kevman 2:7aab896b1a3b 409 if (result == BD_ERROR_OK) {
kevman 2:7aab896b1a3b 410 bytes_written += bytes_remaining;
kevman 2:7aab896b1a3b 411 page_number++;
kevman 2:7aab896b1a3b 412
kevman 2:7aab896b1a3b 413 /* After the first successful write,
kevman 2:7aab896b1a3b 414 all subsequent writes will be aligned.
kevman 2:7aab896b1a3b 415 */
kevman 2:7aab896b1a3b 416 page_offset = 0;
kevman 2:7aab896b1a3b 417 } else {
kevman 2:7aab896b1a3b 418 break;
kevman 2:7aab896b1a3b 419 }
kevman 2:7aab896b1a3b 420 }
kevman 2:7aab896b1a3b 421
kevman 2:7aab896b1a3b 422 /* enable write protection */
kevman 2:7aab896b1a3b 423 _write_enable(false);
kevman 2:7aab896b1a3b 424 }
kevman 2:7aab896b1a3b 425
kevman 2:7aab896b1a3b 426 _mutex.unlock();
kevman 2:7aab896b1a3b 427 return result;
kevman 2:7aab896b1a3b 428 }
kevman 2:7aab896b1a3b 429
kevman 2:7aab896b1a3b 430 int DataFlashBlockDevice::erase(bd_addr_t addr, bd_size_t size)
kevman 2:7aab896b1a3b 431 {
kevman 2:7aab896b1a3b 432 _mutex.lock();
kevman 2:7aab896b1a3b 433 DEBUG_PRINTF("erase: %" PRIX64 " %" PRIX64 "\r\n", addr, size);
kevman 2:7aab896b1a3b 434
kevman 2:7aab896b1a3b 435 if (!_is_initialized) {
kevman 2:7aab896b1a3b 436 _mutex.unlock();
kevman 2:7aab896b1a3b 437 return BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 438 }
kevman 2:7aab896b1a3b 439
kevman 2:7aab896b1a3b 440 int result = BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 441
kevman 2:7aab896b1a3b 442 /* check parameters are valid and the erase is within bounds */
kevman 2:7aab896b1a3b 443 if (is_valid_erase(addr, size)) {
kevman 2:7aab896b1a3b 444
kevman 2:7aab896b1a3b 445 /* disable write protection */
kevman 2:7aab896b1a3b 446 _write_enable(true);
kevman 2:7aab896b1a3b 447
kevman 2:7aab896b1a3b 448 /* erase one block at a time until the full size has been erased */
kevman 2:7aab896b1a3b 449 uint32_t erased = 0;
kevman 2:7aab896b1a3b 450 while (erased < size) {
kevman 2:7aab896b1a3b 451
kevman 2:7aab896b1a3b 452 /* set block erase opcode */
kevman 2:7aab896b1a3b 453 uint32_t command = DATAFLASH_OP_ERASE_BLOCK;
kevman 2:7aab896b1a3b 454
kevman 2:7aab896b1a3b 455 /* translate address */
kevman 2:7aab896b1a3b 456 uint32_t address = _translate_address(addr);
kevman 2:7aab896b1a3b 457
kevman 2:7aab896b1a3b 458 /* set block address */
kevman 2:7aab896b1a3b 459 command = (command << 8) | ((address >> 16) & 0xFF);
kevman 2:7aab896b1a3b 460 command = (command << 8) | ((address >> 8) & 0xFF);
kevman 2:7aab896b1a3b 461 command = (command << 8) | (address & 0xFF);
kevman 2:7aab896b1a3b 462
kevman 2:7aab896b1a3b 463 /* send command to device */
kevman 2:7aab896b1a3b 464 _write_command(command, NULL, 0);
kevman 2:7aab896b1a3b 465
kevman 2:7aab896b1a3b 466 /* wait until device is ready and update return value */
kevman 2:7aab896b1a3b 467 result = _sync();
kevman 2:7aab896b1a3b 468
kevman 2:7aab896b1a3b 469 /* if erase failed, break loop */
kevman 2:7aab896b1a3b 470 if (result != BD_ERROR_OK) {
kevman 2:7aab896b1a3b 471 break;
kevman 2:7aab896b1a3b 472 }
kevman 2:7aab896b1a3b 473
kevman 2:7aab896b1a3b 474 /* update loop variables */
kevman 2:7aab896b1a3b 475 addr += _block_size;
kevman 2:7aab896b1a3b 476 erased += _block_size;
kevman 2:7aab896b1a3b 477 }
kevman 2:7aab896b1a3b 478
kevman 2:7aab896b1a3b 479 /* enable write protection */
kevman 2:7aab896b1a3b 480 _write_enable(false);
kevman 2:7aab896b1a3b 481 }
kevman 2:7aab896b1a3b 482
kevman 2:7aab896b1a3b 483 _mutex.unlock();
kevman 2:7aab896b1a3b 484 return result;
kevman 2:7aab896b1a3b 485 }
kevman 2:7aab896b1a3b 486
kevman 2:7aab896b1a3b 487 bd_size_t DataFlashBlockDevice::get_read_size() const
kevman 2:7aab896b1a3b 488 {
kevman 2:7aab896b1a3b 489 DEBUG_PRINTF("read size: %d\r\n", DATAFLASH_READ_SIZE);
kevman 2:7aab896b1a3b 490
kevman 2:7aab896b1a3b 491 return DATAFLASH_READ_SIZE;
kevman 2:7aab896b1a3b 492 }
kevman 2:7aab896b1a3b 493
kevman 2:7aab896b1a3b 494 bd_size_t DataFlashBlockDevice::get_program_size() const
kevman 2:7aab896b1a3b 495 {
kevman 2:7aab896b1a3b 496 DEBUG_PRINTF("program size: %d\r\n", DATAFLASH_PROG_SIZE);
kevman 2:7aab896b1a3b 497
kevman 2:7aab896b1a3b 498 return DATAFLASH_PROG_SIZE;
kevman 2:7aab896b1a3b 499 }
kevman 2:7aab896b1a3b 500
kevman 2:7aab896b1a3b 501 bd_size_t DataFlashBlockDevice::get_erase_size() const
kevman 2:7aab896b1a3b 502 {
kevman 2:7aab896b1a3b 503 _mutex.lock();
kevman 2:7aab896b1a3b 504 DEBUG_PRINTF("erase size: %" PRIX16 "\r\n", _block_size);
kevman 2:7aab896b1a3b 505 bd_size_t block_size = _block_size;
kevman 2:7aab896b1a3b 506 _mutex.unlock();
kevman 2:7aab896b1a3b 507 return block_size;
kevman 2:7aab896b1a3b 508 }
kevman 2:7aab896b1a3b 509
kevman 2:7aab896b1a3b 510 bd_size_t DataFlashBlockDevice::get_erase_size(bd_addr_t addr) const
kevman 2:7aab896b1a3b 511 {
kevman 2:7aab896b1a3b 512 _mutex.lock();
kevman 2:7aab896b1a3b 513 DEBUG_PRINTF("erase size: %" PRIX16 "\r\n", _block_size);
kevman 2:7aab896b1a3b 514 bd_size_t block_size = _block_size;
kevman 2:7aab896b1a3b 515 _mutex.unlock();
kevman 2:7aab896b1a3b 516 return block_size;
kevman 2:7aab896b1a3b 517 }
kevman 2:7aab896b1a3b 518
kevman 2:7aab896b1a3b 519 bd_size_t DataFlashBlockDevice::size() const
kevman 2:7aab896b1a3b 520 {
kevman 2:7aab896b1a3b 521 _mutex.lock();
kevman 2:7aab896b1a3b 522 DEBUG_PRINTF("device size: %" PRIX32 "\r\n", _device_size);
kevman 2:7aab896b1a3b 523 bd_size_t device_size = _device_size;
kevman 2:7aab896b1a3b 524 _mutex.unlock();
kevman 2:7aab896b1a3b 525 return device_size;
kevman 2:7aab896b1a3b 526 }
kevman 2:7aab896b1a3b 527
kevman 2:7aab896b1a3b 528 /**
kevman 2:7aab896b1a3b 529 * @brief Function for reading a specific register.
kevman 2:7aab896b1a3b 530 * @details Used for reading either the Status Register or Manufacture and ID Register.
kevman 2:7aab896b1a3b 531 *
kevman 2:7aab896b1a3b 532 * @param opcode Register to be read.
kevman 2:7aab896b1a3b 533 * @return value.
kevman 2:7aab896b1a3b 534 */
kevman 2:7aab896b1a3b 535 uint16_t DataFlashBlockDevice::_get_register(uint8_t opcode)
kevman 2:7aab896b1a3b 536 {
kevman 2:7aab896b1a3b 537 _mutex.lock();
kevman 2:7aab896b1a3b 538 DEBUG_PRINTF("_get_register: %" PRIX8 "\r\n", opcode);
kevman 2:7aab896b1a3b 539
kevman 2:7aab896b1a3b 540 /* activate device */
kevman 2:7aab896b1a3b 541 _cs = 0;
kevman 2:7aab896b1a3b 542
kevman 2:7aab896b1a3b 543 /* write opcode */
kevman 2:7aab896b1a3b 544 _spi.write(opcode);
kevman 2:7aab896b1a3b 545
kevman 2:7aab896b1a3b 546 /* read and store result */
kevman 2:7aab896b1a3b 547 int status = (_spi.write(DATAFLASH_OP_NOP));
kevman 2:7aab896b1a3b 548 status = (status << 8) | (_spi.write(DATAFLASH_OP_NOP));
kevman 2:7aab896b1a3b 549
kevman 2:7aab896b1a3b 550 /* deactivate device */
kevman 2:7aab896b1a3b 551 _cs = 1;
kevman 2:7aab896b1a3b 552
kevman 2:7aab896b1a3b 553 _mutex.unlock();
kevman 2:7aab896b1a3b 554 return status;
kevman 2:7aab896b1a3b 555 }
kevman 2:7aab896b1a3b 556
kevman 2:7aab896b1a3b 557 /**
kevman 2:7aab896b1a3b 558 * @brief Function for sending command and data to device.
kevman 2:7aab896b1a3b 559 * @details The command can be an opcode with address and data or
kevman 2:7aab896b1a3b 560 * a 4 byte command without data.
kevman 2:7aab896b1a3b 561 *
kevman 2:7aab896b1a3b 562 * The supported frequencies and the opcode used do not
kevman 2:7aab896b1a3b 563 * require dummy bytes to be sent after command.
kevman 2:7aab896b1a3b 564 *
kevman 2:7aab896b1a3b 565 * @param command Opcode with address or 4 byte command.
kevman 2:7aab896b1a3b 566 * @param buffer Data to be sent after command.
kevman 2:7aab896b1a3b 567 * @param size Size of buffer.
kevman 2:7aab896b1a3b 568 */
kevman 2:7aab896b1a3b 569 void DataFlashBlockDevice::_write_command(uint32_t command, const uint8_t *buffer, uint32_t size)
kevman 2:7aab896b1a3b 570 {
kevman 2:7aab896b1a3b 571 DEBUG_PRINTF("_write_command: %" PRIX32 " %p %" PRIX32 "\r\n", command, buffer, size);
kevman 2:7aab896b1a3b 572
kevman 2:7aab896b1a3b 573 /* activate device */
kevman 2:7aab896b1a3b 574 _cs = 0;
kevman 2:7aab896b1a3b 575
kevman 2:7aab896b1a3b 576 /* send command (opcode with data or 4 byte command) */
kevman 2:7aab896b1a3b 577 _spi.write((command >> 24) & 0xFF);
kevman 2:7aab896b1a3b 578 _spi.write((command >> 16) & 0xFF);
kevman 2:7aab896b1a3b 579 _spi.write((command >> 8) & 0xFF);
kevman 2:7aab896b1a3b 580 _spi.write(command & 0xFF);
kevman 2:7aab896b1a3b 581
kevman 2:7aab896b1a3b 582 /* send optional data */
kevman 2:7aab896b1a3b 583 if (buffer && size) {
kevman 2:7aab896b1a3b 584 for (uint32_t index = 0; index < size; index++) {
kevman 2:7aab896b1a3b 585 _spi.write(buffer[index]);
kevman 2:7aab896b1a3b 586 }
kevman 2:7aab896b1a3b 587 }
kevman 2:7aab896b1a3b 588
kevman 2:7aab896b1a3b 589 /* deactivate device */
kevman 2:7aab896b1a3b 590 _cs = 1;
kevman 2:7aab896b1a3b 591 }
kevman 2:7aab896b1a3b 592
kevman 2:7aab896b1a3b 593 /**
kevman 2:7aab896b1a3b 594 * @brief Enable and disable write protection.
kevman 2:7aab896b1a3b 595 *
kevman 2:7aab896b1a3b 596 * @param enable Boolean for enabling or disabling write protection.
kevman 2:7aab896b1a3b 597 */
kevman 2:7aab896b1a3b 598 void DataFlashBlockDevice::_write_enable(bool enable)
kevman 2:7aab896b1a3b 599 {
kevman 2:7aab896b1a3b 600 DEBUG_PRINTF("_write_enable: %d\r\n", enable);
kevman 2:7aab896b1a3b 601
kevman 2:7aab896b1a3b 602 /* enable writing, disable write protection */
kevman 2:7aab896b1a3b 603 if (enable) {
kevman 2:7aab896b1a3b 604 /* if not-write-protected pin is connected, select it */
kevman 2:7aab896b1a3b 605 if (_nwp.is_connected()) {
kevman 2:7aab896b1a3b 606 _nwp = 1;
kevman 2:7aab896b1a3b 607 }
kevman 2:7aab896b1a3b 608
kevman 2:7aab896b1a3b 609 /* send 4 byte command enabling writes */
kevman 2:7aab896b1a3b 610 _write_command(DATAFLASH_COMMAND_WRITE_ENABLE, NULL, 0);
kevman 2:7aab896b1a3b 611 } else {
kevman 2:7aab896b1a3b 612
kevman 2:7aab896b1a3b 613 /* if not-write-protected pin is connected, deselect it */
kevman 2:7aab896b1a3b 614 if (_nwp.is_connected()) {
kevman 2:7aab896b1a3b 615 _nwp = 0;
kevman 2:7aab896b1a3b 616 }
kevman 2:7aab896b1a3b 617
kevman 2:7aab896b1a3b 618 /* send 4 byte command disabling writes */
kevman 2:7aab896b1a3b 619 _write_command(DATAFLASH_COMMAND_WRITE_DISABLE, NULL, 0);
kevman 2:7aab896b1a3b 620 }
kevman 2:7aab896b1a3b 621 }
kevman 2:7aab896b1a3b 622
kevman 2:7aab896b1a3b 623 /**
kevman 2:7aab896b1a3b 624 * @brief Sleep and poll status register until device is ready for next command.
kevman 2:7aab896b1a3b 625 *
kevman 2:7aab896b1a3b 626 * @return BlockDevice compatible error code.
kevman 2:7aab896b1a3b 627 */
kevman 2:7aab896b1a3b 628 int DataFlashBlockDevice::_sync(void)
kevman 2:7aab896b1a3b 629 {
kevman 2:7aab896b1a3b 630 DEBUG_PRINTF("_sync\r\n");
kevman 2:7aab896b1a3b 631
kevman 2:7aab896b1a3b 632 /* default return value if operation times out */
kevman 2:7aab896b1a3b 633 int result = BD_ERROR_DEVICE_ERROR;
kevman 2:7aab896b1a3b 634
kevman 2:7aab896b1a3b 635 /* Poll device until a hard coded timeout is reached.
kevman 2:7aab896b1a3b 636 The polling interval is based on the typical page program time.
kevman 2:7aab896b1a3b 637 */
kevman 2:7aab896b1a3b 638 for (uint32_t timeout = 0;
kevman 2:7aab896b1a3b 639 timeout < DATAFLASH_TIMEOUT;
kevman 2:7aab896b1a3b 640 timeout += DATAFLASH_TIMING_ERASE_PROGRAM_PAGE) {
kevman 2:7aab896b1a3b 641
kevman 2:7aab896b1a3b 642 /* get status register */
kevman 2:7aab896b1a3b 643 uint16_t status = _get_register(DATAFLASH_OP_STATUS);
kevman 2:7aab896b1a3b 644
kevman 2:7aab896b1a3b 645 /* erase/program bit set, exit with error code set */
kevman 2:7aab896b1a3b 646 if (status & DATAFLASH_BIT_ERASE_PROGRAM_ERROR) {
kevman 2:7aab896b1a3b 647 DEBUG_PRINTF("DATAFLASH_BIT_ERASE_PROGRAM_ERROR\r\n");
kevman 2:7aab896b1a3b 648 break;
kevman 2:7aab896b1a3b 649 /* device ready, set OK code set */
kevman 2:7aab896b1a3b 650 } else if (status & DATAFLASH_BIT_READY) {
kevman 2:7aab896b1a3b 651 DEBUG_PRINTF("DATAFLASH_BIT_READY\r\n");
kevman 2:7aab896b1a3b 652 result = BD_ERROR_OK;
kevman 2:7aab896b1a3b 653 break;
kevman 2:7aab896b1a3b 654 /* wait the typical write period before trying again */
kevman 2:7aab896b1a3b 655 } else {
kevman 2:7aab896b1a3b 656 DEBUG_PRINTF("wait_ms: %d\r\n", DATAFLASH_TIMING_ERASE_PROGRAM_PAGE);
kevman 2:7aab896b1a3b 657 wait_ms(DATAFLASH_TIMING_ERASE_PROGRAM_PAGE);
kevman 2:7aab896b1a3b 658 }
kevman 2:7aab896b1a3b 659 }
kevman 2:7aab896b1a3b 660
kevman 2:7aab896b1a3b 661 return result;
kevman 2:7aab896b1a3b 662 }
kevman 2:7aab896b1a3b 663
kevman 2:7aab896b1a3b 664 /**
kevman 2:7aab896b1a3b 665 * @brief Write single page.
kevman 2:7aab896b1a3b 666 * @details Address can be unaligned.
kevman 2:7aab896b1a3b 667 *
kevman 2:7aab896b1a3b 668 * @param buffer Data to write.
kevman 2:7aab896b1a3b 669 * @param addr Address to write from.
kevman 2:7aab896b1a3b 670 * @param size Bytes to write. Can at most be the full page.
kevman 2:7aab896b1a3b 671 * @return BlockDevice error code.
kevman 2:7aab896b1a3b 672 */
kevman 2:7aab896b1a3b 673 int DataFlashBlockDevice::_write_page(const uint8_t *buffer,
kevman 2:7aab896b1a3b 674 uint32_t page,
kevman 2:7aab896b1a3b 675 uint32_t offset,
kevman 2:7aab896b1a3b 676 uint32_t size)
kevman 2:7aab896b1a3b 677 {
kevman 2:7aab896b1a3b 678 DEBUG_PRINTF("_write_page: %p %" PRIX32 " %" PRIX32 "\r\n", buffer, page, size);
kevman 2:7aab896b1a3b 679
kevman 2:7aab896b1a3b 680 uint32_t command = DATAFLASH_OP_NOP;
kevman 2:7aab896b1a3b 681
kevman 2:7aab896b1a3b 682 /* opcode for writing directly to device, in a single command,
kevman 2:7aab896b1a3b 683 assuming the page has been erased before hand.
kevman 2:7aab896b1a3b 684 */
kevman 2:7aab896b1a3b 685 command = DATAFLASH_OP_PROGRAM_DIRECT;
kevman 2:7aab896b1a3b 686
kevman 2:7aab896b1a3b 687 uint32_t address = 0;
kevman 2:7aab896b1a3b 688
kevman 2:7aab896b1a3b 689 /* convert page number and offset into device address based on address format */
kevman 2:7aab896b1a3b 690 if (_page_size == DATAFLASH_PAGE_SIZE_264) {
kevman 2:7aab896b1a3b 691 address = (page << DATAFLASH_PAGE_BIT_264) | offset;
kevman 2:7aab896b1a3b 692 } else if (_page_size == DATAFLASH_PAGE_SIZE_528) {
kevman 2:7aab896b1a3b 693 address = (page << DATAFLASH_PAGE_BIT_528) | offset;
kevman 2:7aab896b1a3b 694 } else {
kevman 2:7aab896b1a3b 695 address = (page * _page_size) | offset;
kevman 2:7aab896b1a3b 696 }
kevman 2:7aab896b1a3b 697
kevman 2:7aab896b1a3b 698 /* set write address */
kevman 2:7aab896b1a3b 699 command = (command << 8) | ((address >> 16) & 0xFF);
kevman 2:7aab896b1a3b 700 command = (command << 8) | ((address >> 8) & 0xFF);
kevman 2:7aab896b1a3b 701 command = (command << 8) | (address & 0xFF);
kevman 2:7aab896b1a3b 702
kevman 2:7aab896b1a3b 703 /* send write command with data */
kevman 2:7aab896b1a3b 704 _write_command(command, buffer, size);
kevman 2:7aab896b1a3b 705
kevman 2:7aab896b1a3b 706 /* wait until device is ready before continuing */
kevman 2:7aab896b1a3b 707 int result = _sync();
kevman 2:7aab896b1a3b 708
kevman 2:7aab896b1a3b 709 return result;
kevman 2:7aab896b1a3b 710 }
kevman 2:7aab896b1a3b 711
kevman 2:7aab896b1a3b 712 /**
kevman 2:7aab896b1a3b 713 * @brief Translate address.
kevman 2:7aab896b1a3b 714 * @details If the device is configured for non-binary page sizes,
kevman 2:7aab896b1a3b 715 * the address is translated from binary to non-binary form.
kevman 2:7aab896b1a3b 716 *
kevman 2:7aab896b1a3b 717 * @param addr Binary address.
kevman 2:7aab896b1a3b 718 * @return Address in format expected by device.
kevman 2:7aab896b1a3b 719 */
kevman 2:7aab896b1a3b 720 uint32_t DataFlashBlockDevice::_translate_address(bd_addr_t addr)
kevman 2:7aab896b1a3b 721 {
kevman 2:7aab896b1a3b 722 uint32_t address = addr;
kevman 2:7aab896b1a3b 723
kevman 2:7aab896b1a3b 724 /* translate address if page size is non-binary */
kevman 2:7aab896b1a3b 725 if (_page_size == DATAFLASH_PAGE_SIZE_264) {
kevman 2:7aab896b1a3b 726 address = ((addr / DATAFLASH_PAGE_SIZE_264) << DATAFLASH_PAGE_BIT_264) |
kevman 2:7aab896b1a3b 727 (addr % DATAFLASH_PAGE_SIZE_264);
kevman 2:7aab896b1a3b 728 } else if (_page_size == DATAFLASH_PAGE_SIZE_528) {
kevman 2:7aab896b1a3b 729 address = ((addr / DATAFLASH_PAGE_SIZE_528) << DATAFLASH_PAGE_BIT_528) |
kevman 2:7aab896b1a3b 730 (addr % DATAFLASH_PAGE_SIZE_528);
kevman 2:7aab896b1a3b 731 }
kevman 2:7aab896b1a3b 732
kevman 2:7aab896b1a3b 733 return address;
kevman 2:7aab896b1a3b 734 }
kevman 2:7aab896b1a3b 735
kevman 2:7aab896b1a3b 736 /**
kevman 2:7aab896b1a3b 737 * @brief Internal function for printing out each bit set in status register.
kevman 2:7aab896b1a3b 738 *
kevman 2:7aab896b1a3b 739 * @param status Status register.
kevman 2:7aab896b1a3b 740 */
kevman 2:7aab896b1a3b 741 void _print_status(uint16_t status)
kevman 2:7aab896b1a3b 742 {
kevman 2:7aab896b1a3b 743 #if DATAFLASH_DEBUG
kevman 2:7aab896b1a3b 744 DEBUG_PRINTF("%04X\r\n", status);
kevman 2:7aab896b1a3b 745
kevman 2:7aab896b1a3b 746 /* device is ready (after write/erase) */
kevman 2:7aab896b1a3b 747 if (status & DATAFLASH_BIT_READY) {
kevman 2:7aab896b1a3b 748 DEBUG_PRINTF("DATAFLASH_BIT_READY\r\n");
kevman 2:7aab896b1a3b 749 }
kevman 2:7aab896b1a3b 750
kevman 2:7aab896b1a3b 751 /* Buffer comparison failed */
kevman 2:7aab896b1a3b 752 if (status & DATAFLASH_BIT_COMPARE) {
kevman 2:7aab896b1a3b 753 DEBUG_PRINTF("DATAFLASH_BIT_COMPARE\r\n");
kevman 2:7aab896b1a3b 754 }
kevman 2:7aab896b1a3b 755
kevman 2:7aab896b1a3b 756 /* device size is 2 MB */
kevman 2:7aab896b1a3b 757 if (status & DATAFLASH_STATUS_DENSITY_2_MBIT) {
kevman 2:7aab896b1a3b 758 DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_2_MBIT\r\n");
kevman 2:7aab896b1a3b 759 }
kevman 2:7aab896b1a3b 760
kevman 2:7aab896b1a3b 761 /* device size is 4 MB */
kevman 2:7aab896b1a3b 762 if (status & DATAFLASH_STATUS_DENSITY_4_MBIT) {
kevman 2:7aab896b1a3b 763 DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_4_MBIT\r\n");
kevman 2:7aab896b1a3b 764 }
kevman 2:7aab896b1a3b 765
kevman 2:7aab896b1a3b 766 /* device size is 8 MB */
kevman 2:7aab896b1a3b 767 if (status & DATAFLASH_STATUS_DENSITY_8_MBIT) {
kevman 2:7aab896b1a3b 768 DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_8_MBIT\r\n");
kevman 2:7aab896b1a3b 769 }
kevman 2:7aab896b1a3b 770
kevman 2:7aab896b1a3b 771 /* device size is 16 MB */
kevman 2:7aab896b1a3b 772 if (status & DATAFLASH_STATUS_DENSITY_16_MBIT) {
kevman 2:7aab896b1a3b 773 DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_16_MBIT\r\n");
kevman 2:7aab896b1a3b 774 }
kevman 2:7aab896b1a3b 775
kevman 2:7aab896b1a3b 776 /* device size is 32 MB */
kevman 2:7aab896b1a3b 777 if (status & DATAFLASH_STATUS_DENSITY_32_MBIT) {
kevman 2:7aab896b1a3b 778 DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_32_MBIT\r\n");
kevman 2:7aab896b1a3b 779 }
kevman 2:7aab896b1a3b 780
kevman 2:7aab896b1a3b 781 /* device size is 64 MB */
kevman 2:7aab896b1a3b 782 if (status & DATAFLASH_STATUS_DENSITY_64_MBIT) {
kevman 2:7aab896b1a3b 783 DEBUG_PRINTF("DATAFLASH_STATUS_DENSITY_64_MBIT\r\n");
kevman 2:7aab896b1a3b 784 }
kevman 2:7aab896b1a3b 785
kevman 2:7aab896b1a3b 786 /* sector protectino enabled */
kevman 2:7aab896b1a3b 787 if (status & DATAFLASH_BIT_PROTECT) {
kevman 2:7aab896b1a3b 788 DEBUG_PRINTF("DATAFLASH_BIT_PROTECT\r\n");
kevman 2:7aab896b1a3b 789 }
kevman 2:7aab896b1a3b 790
kevman 2:7aab896b1a3b 791 /* page size is a power of 2 */
kevman 2:7aab896b1a3b 792 if (status & DATAFLASH_BIT_PAGE_SIZE) {
kevman 2:7aab896b1a3b 793 DEBUG_PRINTF("DATAFLASH_BIT_PAGE_SIZE\r\n");
kevman 2:7aab896b1a3b 794 }
kevman 2:7aab896b1a3b 795
kevman 2:7aab896b1a3b 796 /* erase/program error */
kevman 2:7aab896b1a3b 797 if (status & DATAFLASH_BIT_ERASE_PROGRAM_ERROR) {
kevman 2:7aab896b1a3b 798 DEBUG_PRINTF("DATAFLASH_BIT_ERASE_PROGRAM_ERROR\r\n");
kevman 2:7aab896b1a3b 799 }
kevman 2:7aab896b1a3b 800
kevman 2:7aab896b1a3b 801 /* sector lockdown still possible */
kevman 2:7aab896b1a3b 802 if (status & DATAFLASH_BIT_SECTOR_LOCKDOWN) {
kevman 2:7aab896b1a3b 803 DEBUG_PRINTF("DATAFLASH_BIT_SECTOR_LOCKDOWN\r\n");
kevman 2:7aab896b1a3b 804 }
kevman 2:7aab896b1a3b 805
kevman 2:7aab896b1a3b 806 /* program operation suspended while using buffer 2 */
kevman 2:7aab896b1a3b 807 if (status & DATAFLASH_BIT_PROGRAM_SUSPEND_2) {
kevman 2:7aab896b1a3b 808 DEBUG_PRINTF("DATAFLASH_BIT_PROGRAM_SUSPEND_2\r\n");
kevman 2:7aab896b1a3b 809 }
kevman 2:7aab896b1a3b 810
kevman 2:7aab896b1a3b 811 /* program operation suspended while using buffer 1 */
kevman 2:7aab896b1a3b 812 if (status & DATAFLASH_BIT_PROGRAM_SUSPEND_1) {
kevman 2:7aab896b1a3b 813 DEBUG_PRINTF("DATAFLASH_BIT_PROGRAM_SUSPEND_1\r\n");
kevman 2:7aab896b1a3b 814 }
kevman 2:7aab896b1a3b 815
kevman 2:7aab896b1a3b 816 /* erase has been suspended */
kevman 2:7aab896b1a3b 817 if (status & DATAFLASH_BIT_ERASE_SUSPEND) {
kevman 2:7aab896b1a3b 818 DEBUG_PRINTF("DATAFLASH_BIT_ERASE_SUSPEND\r\n");
kevman 2:7aab896b1a3b 819 }
kevman 2:7aab896b1a3b 820 #endif
kevman 2:7aab896b1a3b 821 }