CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
Ardupilot

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: Ardupilot/ardupilot
Path: blob/master/libraries/AP_FlashIface/AP_FlashIface_JEDEC.cpp
Views: 1798
1
/*
2
* This file is free software: you can redistribute it and/or modify it
3
* under the terms of the GNU General Public License as published by the
4
* Free Software Foundation, either version 3 of the License, or
5
* (at your option) any later version.
6
*
7
* This file is distributed in the hope that it will be useful, but
8
* WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
* See the GNU General Public License for more details.
11
*
12
* You should have received a copy of the GNU General Public License along
13
* with this program. If not, see <http://www.gnu.org/licenses/>.
14
*
15
* Code by
16
* Andy Piper
17
* Siddharth Bharat Purohit, Cubepilot Pty. Ltd.
18
*/
19
/*
20
Implements Common Flash Interface Driver based on following
21
standard published by JEDEC
22
* JEDEC Standard, JESD216D, Serial Flash Discoverable Parameters (SFDP)
23
*/
24
25
#include <AP_HAL/AP_HAL.h>
26
#include "AP_FlashIface_JEDEC.h"
27
#include <AP_Math/AP_Math.h>
28
#ifdef HAL_BOOTLOADER_BUILD
29
#include <AP_HAL_ChibiOS/WSPIDevice.h>
30
#include "../../Tools/AP_Bootloader/support.h"
31
#else
32
extern const AP_HAL::HAL& hal;
33
#endif
34
35
enum class SupportedDeviceType {
36
QuadSPI = 0,
37
OctoSPI = 1
38
};
39
40
struct supported_device {
41
const char* name;
42
uint8_t manufacturer_id;
43
uint8_t device_id;
44
SupportedDeviceType device_type;
45
};
46
47
static const struct supported_device supported_devices[] = {
48
{"mt25q", 0x20, 0xBA, SupportedDeviceType::QuadSPI}, // https://www.mouser.in/datasheet/2/671/mict_s_a0003959700_1-2290909.pdf
49
{"w25q", 0xEF, 0x40, SupportedDeviceType::QuadSPI},
50
{"w25q-dtr", 0xEF, 0x70, SupportedDeviceType::QuadSPI},
51
};
52
53
#ifdef HAL_BOOTLOADER_BUILD
54
#define DELAY_MILLIS(x) do { chThdSleepMilliseconds(x); } while(0)
55
#define DELAY_MICROS(x) do { chThdSleepMicroseconds(x); } while(0)
56
#else
57
#define DELAY_MILLIS(x) do { hal.scheduler->delay(x); } while(0)
58
#define DELAY_MICROS(x) do { hal.scheduler->delay_microseconds(x); } while(0)
59
#endif
60
61
#define MAX_SUPPORTED_FLASH_SIZE 0x1FFFFFFUL
62
// Vendor Specific Constants
63
// Following Commands Sets were found here:
64
// * JEDEC Standard JESD251-A1, Addendum No. 1 to JESD251, Optional x4 Quad I/O
65
// With Data Strobe
66
/// NOTE: Except Read ID and Multiline Read ID, they seem to be
67
// constant across manufacturers, but can't find official standard on
68
// this.
69
#define CMD_READ_ID 0x9F
70
#define CMD_MULTILINE_READ_ID 0xAF
71
#define CMD_PAGE_PROGRAM 0x02
72
#define CMD_WRITE_DISABLE 0x04
73
#define CMD_READ_STATUS_1 0x05
74
#define CMD_READ_STATUS_2 0x35
75
#define CMD_MASS_ERASE 0xC7
76
#define CMD_RESET_ENABLE 0x66
77
#define CMD_RESET_MEMORY 0x99
78
#define CMD_READ_SFDP 0x5A
79
80
#define SFDP_MASK(lo, hi) (((1UL<<(hi)) - ((1UL<<(lo)))) + (1UL<<(hi)))
81
#define SFDP_GET_BITS(x, lo, hi) (((x) & SFDP_MASK(lo, hi)) >> (lo))
82
#define SFDP_GET_BIT(x, bit) ((x) & (1<<(bit)))
83
84
#define SFDP_HDR_NUM_PARAMS(x) (SFDP_GET_BITS(x[1], 16, 19) + 1)
85
#define SFDP_HDR_PARAM_REV(x) SFDP_GET_BITS(x[1], 0, 15)
86
#define SFDP_PARAM_ID(x) ((SFDP_GET_BITS(x[0], 0, 3) << 8) | SFDP_GET_BITS(x[1], 24, 31))
87
#define SFDP_PARAM_DWORD_LEN(x) SFDP_GET_BITS(x[0], 24, 31)
88
#define SFDP_PARAM_POINTER(x) SFDP_GET_BITS(x[1], 0, 23)
89
90
#define SFDP_REV_1_5 0x0105
91
#define SFDP_REV_1_6 0x0106
92
// quad enable for winbond
93
#define QUAD_ENABLE_B1R2 0x4
94
// octo enable for winbond
95
#define OCTO_ENABLE_B3R2 0x1
96
97
//#define DEBUG
98
99
#ifdef HAL_BOOTLOADER_BUILD
100
#ifdef DEBUG
101
#define Debug(fmt, args ...) do {uprintf("JEDEC: " fmt "\n", ## args);} while(0)
102
#else
103
#define Debug(fmt, args ...)
104
#endif
105
#define Msg_Print(fmt, args ...) do {uprintf("JEDEC: " fmt "\n", ## args);} while(0)
106
#else
107
#ifdef DEBUG
108
#define Debug(fmt, args ...) do {hal.console->printf("JEDEC: " fmt "\n", ## args);} while(0)
109
#else
110
#define Debug(fmt, args ...)
111
#endif
112
#define Msg_Print(fmt, args ...) do {hal.console->printf("JEDEC: " fmt "\n", ## args);} while(0)
113
#endif // #ifdef HAL_BOOTLOADER_BUILD
114
115
#define MAX_READ_SIZE 1024UL
116
117
#ifdef HAL_BOOTLOADER_BUILD
118
static ChibiOS::WSPIDeviceManager wspi;
119
#endif
120
121
bool AP_FlashIface_JEDEC::init()
122
{
123
// Get device bus by name
124
_dev = nullptr;
125
for (uint8_t i = 0; i < ARRAY_SIZE(supported_devices); i++) {
126
#ifdef HAL_BOOTLOADER_BUILD
127
_dev = wspi.get_device(supported_devices[i].name);
128
#else
129
_dev = hal.wspi->get_device(supported_devices[i].name);
130
#endif
131
if (_dev) {
132
_dev_list_idx = i;
133
break;
134
}
135
}
136
137
if (!_dev) {
138
AP_HAL::panic("Ext Flash Not Found!");
139
}
140
141
DELAY_MILLIS(5); // required by w25q
142
// Reset Device involves trying to soft reset the chip
143
// as when system reboots the device might not have.
144
reset_device();
145
146
DELAY_MICROS(30); // required by w25q
147
148
// Detecting Device involves trying to read Device ID and matching
149
// with what we expect. Along with extracting info from SFDP
150
if (!detect_device()) {
151
Msg_Print("Failed to detect flash device: %s", supported_devices[_dev_list_idx].name);
152
return false;
153
}
154
155
// Configuring Device involved setting chip to correct WSPI mode
156
// i.e. 1-4-4
157
if (!configure_device()) {
158
Msg_Print("Failed to config flash device: %s", supported_devices[_dev_list_idx].name);
159
return false;
160
}
161
162
Msg_Print("Detected Flash Device: %s", supported_devices[_dev_list_idx].name);
163
return true;
164
}
165
166
//////////////////////////////////////////////////////
167
////////////////// Internal Methods //////////////////
168
//////////////////////////////////////////////////////
169
170
// reset chip to known default power on state
171
void AP_FlashIface_JEDEC::reset_device()
172
{
173
// Get chip out of XIP mode
174
AP_HAL::WSPIDevice::CommandHeader cmd;
175
#ifndef HAL_BOOTLOADER_BUILD // this is required in order to run jedec_test with a regular bootloader
176
_dev->get_semaphore()->take_blocking();
177
#endif
178
179
/* Single line CMD_RESET_MEMORY command.*/
180
cmd.cmd = CMD_RESET_ENABLE;
181
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE;
182
cmd.addr = 0;
183
cmd.alt = 0;
184
cmd.dummy = 0;
185
_dev->set_cmd_header(cmd);
186
_dev->transfer(nullptr, 0, nullptr, 0);
187
188
189
/* Single line N25Q_CMD_RESET_MEMORY command.*/
190
cmd.cmd = CMD_RESET_MEMORY;
191
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE;
192
cmd.addr = 0;
193
cmd.alt = 0;
194
cmd.dummy = 0;
195
_dev->set_cmd_header(cmd);
196
_dev->transfer(nullptr, 0, nullptr, 0);
197
198
// By now we are pretty sure the chip is reset
199
}
200
201
// Does initial configuration to bring up and setup chip
202
bool AP_FlashIface_JEDEC::detect_device()
203
{
204
AP_HAL::WSPIDevice::CommandHeader cmd;
205
206
{
207
uint8_t buf[3] {};
208
cmd.cmd = CMD_READ_ID;
209
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
210
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE;
211
cmd.addr = 0;
212
cmd.alt = 0;
213
cmd.dummy = 0;
214
215
_dev->set_cmd_header(cmd);
216
if (!_dev->transfer(nullptr, 0, buf, sizeof(buf))) {
217
Debug("Failed to read Device ID");
218
return false;
219
}
220
221
if (buf[0] != supported_devices[_dev_list_idx].manufacturer_id ||
222
buf[1] != supported_devices[_dev_list_idx].device_id) {
223
return false;
224
}
225
}
226
227
// Read SFDP header to get information Ref. JESD216D 4 and 6.2
228
{
229
uint32_t sfdp_header[2];
230
231
cmd.cmd = CMD_READ_SFDP;
232
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
233
AP_HAL::WSPI::CFG_ADDR_MODE_ONE_LINE |
234
AP_HAL::WSPI::CFG_ADDR_SIZE_24 |
235
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE;
236
cmd.addr = 0;
237
cmd.alt = 0;
238
cmd.dummy = 8; // 8 dummy cycles
239
_dev->set_cmd_header(cmd);
240
if (!_dev->transfer(nullptr, 0, (uint8_t*)sfdp_header, sizeof(sfdp_header))) {
241
Debug("SFDP Header read failed");
242
return false;
243
}
244
245
// Read Signature
246
if (memcmp(sfdp_header, "SFDP", 4)) {
247
Debug("SFDP Bad Signature: 0x%lx", (unsigned long)sfdp_header[0]);
248
return false;
249
}
250
251
// Read Num Param Headers
252
if (SFDP_HDR_NUM_PARAMS(sfdp_header) == 0) {
253
Debug("Unsupported number of param headers %ld", (unsigned long)SFDP_HDR_NUM_PARAMS(sfdp_header));
254
return false;
255
}
256
// Read Revision
257
_desc.param_rev = SFDP_HDR_PARAM_REV(sfdp_header);
258
if (_desc.param_rev != SFDP_REV_1_6 && _desc.param_rev != SFDP_REV_1_5) {
259
Debug("Unsupported revision %x", (unsigned int)_desc.param_rev);
260
return false;
261
}
262
}
263
264
265
// Read Param Header Ref. JESD216D 6.4.1 6.4.2
266
{
267
uint32_t param_header[2] {}; // read only first parameter header
268
// Immediately after 2 DWORDS of SFDP Header
269
cmd.addr = 2*sizeof(uint32_t);
270
_dev->set_cmd_header(cmd);
271
if (!_dev->transfer(nullptr, 0, (uint8_t*)param_header, sizeof(param_header))) {
272
Debug("Param header read failed");
273
return false;
274
}
275
276
if (SFDP_PARAM_ID(param_header) != 0xFF) {
277
Debug("Only basic Param Table supported not %lx", (unsigned long)SFDP_PARAM_ID(param_header));
278
return false;
279
}
280
// Lets get the length of parameter table
281
_desc.param_table_len = MIN(SFDP_PARAM_DWORD_LEN(param_header), 20UL);
282
_desc.param_table_pointer = SFDP_PARAM_POINTER(param_header);
283
}
284
285
// Read and parse the param table
286
{
287
uint32_t param_table[20] {};
288
cmd.addr = _desc.param_table_pointer;
289
_dev->set_cmd_header(cmd);
290
if (!_dev->transfer(nullptr, 0, (uint8_t*)param_table, _desc.param_table_len*sizeof(uint32_t))) {
291
Debug("Failed to read Parameter Table");
292
return false;
293
}
294
295
// Flash Memory details Ref. JESD216D 6.4.5 6.4.14
296
if (SFDP_GET_BIT(param_table[1], 31)) {
297
Debug("Unsupported Flash Size");
298
return false;
299
}
300
_desc.flash_size = SFDP_GET_BITS(param_table[1], 0, 30)/8;
301
// But we only support 24bit (3Bytes) addressing right now
302
// So limit is upto 32MB addressing
303
if (_desc.flash_size >= MAX_SUPPORTED_FLASH_SIZE) {
304
_desc.flash_size = MAX_SUPPORTED_FLASH_SIZE;
305
}
306
_desc.page_size = 1UL<<SFDP_GET_BITS(param_table[10], 4, 7);
307
_desc.page_count = _desc.flash_size/_desc.page_size;
308
if (_desc.page_count == 0) {
309
Debug("Page size greater than flash size unsupported");
310
return false;
311
}
312
313
// Erase Flash Memory details Ref. JESD216D 6.4.11 6.4.12
314
for (uint8_t i = 0; i < 4; i++) {
315
uint32_t size = 1UL<<SFDP_GET_BITS(param_table[7 + (i/2)], 0 + 16*(i%2), 7 + 16*(i%2));
316
uint8_t ins = SFDP_GET_BITS(param_table[7 + (i/2)], 8 + 16*(i%2), 15 + 16*(i%2));
317
if ((size-1) > 0) {
318
_desc.erase_type[i].size = size;
319
_desc.erase_type[i].ins = ins;
320
if (size > _desc.sector_size) {
321
_desc.sector_size = size;
322
}
323
if (size < _desc.min_erase_size) {
324
_desc.min_erase_size = size;
325
}
326
}
327
}
328
_desc.sector_count = _desc.flash_size/_desc.sector_size;
329
if (_desc.sector_count == 0) {
330
_desc.sector_count = 1;
331
}
332
// Read Erase Times 6.4.13
333
uint8_t timeout_mult = 2*(SFDP_GET_BITS(param_table[9], 0, 3) + 1);
334
for (uint8_t i = 0; i < 4; i++) {
335
if (_desc.erase_type[i].size) {
336
uint32_t unit = SFDP_GET_BITS(param_table[9], 9+(7*i), 10+(7*i));
337
uint8_t val = SFDP_GET_BITS(param_table[9], 4+(7*i), 8+(7*i));
338
if (unit == 0b00) {
339
unit = 1; //1ms
340
} else if (unit == 0b01) {
341
unit = 16; // 16ms
342
} else if (unit == 0b10) {
343
unit = 128; // 128ms
344
} else if (unit == 0b11) {
345
unit = 1000; // 1s
346
}
347
348
_desc.erase_type[i].delay_ms = (val+1)*unit;
349
_desc.erase_type[i].timeout_ms = timeout_mult*_desc.erase_type[i].delay_ms;
350
}
351
}
352
// Mass Erase times 6.4.14
353
uint32_t unit = SFDP_GET_BITS(param_table[10], 29, 30);
354
if (unit == 0b00) {
355
unit = 16; // 16ms
356
} else if (unit == 0b01) {
357
unit = 256; // 256ms
358
} else if (unit == 0b10) {
359
unit = 4000; // 4s
360
} else if (unit == 0b11) {
361
unit = 64000; // 64s
362
}
363
_desc.mass_erase_delay_ms = (SFDP_GET_BITS(param_table[10], 24, 28) + 1)*unit;
364
_desc.mass_erase_timeout_ms = timeout_mult*_desc.mass_erase_delay_ms;
365
366
// Setup Write Enable Instruction Ref. JESD216D 6.4.19
367
// If needed legacy support Ref. JESD216D 6.4.4 and implement that
368
if (SFDP_GET_BIT(param_table[15], 0) ||
369
SFDP_GET_BIT(param_table[15], 1)) {
370
_desc.write_enable_ins = 0x06;
371
} else if (SFDP_GET_BIT(param_table[15], 2)) {
372
_desc.write_enable_ins = 0x50;
373
} else if (SFDP_GET_BITS(param_table[15], 3, 6)) {
374
Debug("Unsupported Register Write Enable Config");
375
return false;
376
}
377
378
// Setup Program timings Ref. JESD216D 6.4.14
379
// unit = SFDP_GET_BIT(param_table[10], 23)?1:8;
380
// _desc.add_byte_prog_delay_us = (SFDP_GET_BITS(19, 22) + 1) * unit;
381
// _desc.add_byte_prog_timeout_us = _desc.add_byte_prog_delay_us * timeout_mult;
382
// unit = SFDP_GET_BIT(param_table[10], 18)?1:8;
383
// _desc.first_byte_prog_delay_us = (SFDP_GET_BITS(14, 17) + 1) * unit;
384
// _desc.first_byte_prog_timeout_us = _desc.first_byte_prog_delay_us * timeout_mult;
385
386
// Implement above code if more precise delay and timeouts are needed while programming
387
// otherwise fraction of page timings should be fine
388
timeout_mult = 2*(SFDP_GET_BITS(param_table[10], 0, 3) + 1);
389
unit = SFDP_GET_BIT(param_table[10], 13)?64:8;
390
_desc.page_prog_delay_us = (SFDP_GET_BITS(param_table[10], 8, 12) + 1) * unit;
391
_desc.page_prog_timeout_us = _desc.page_prog_delay_us * timeout_mult;
392
393
uint8_t fast_read_dword = 2; // QuadSPI configuration dword
394
#if HAL_USE_OCTOSPI
395
// To use Octo SPI it must be both supported in hardware and configured
396
const bool octo_spi = supported_devices[_dev_list_idx].device_type == SupportedDeviceType::OctoSPI
397
&& SFDP_GET_BITS(param_table[16], 8, 15);
398
399
if (octo_spi) {
400
fast_read_dword = 16;
401
}
402
#else
403
const bool octo_spi = false;
404
#endif
405
406
// Configure Octo/Quad Mode Enable and Read Sequence, Ref. JESD216D 6.4.8 6.4.10 6.4.18, 6.4.20
407
if (!octo_spi && !SFDP_GET_BIT(param_table[0], 21)) {
408
Debug("1-4-4 mode unsupported");
409
return false;
410
}
411
412
_desc.fast_read_ins = SFDP_GET_BITS(param_table[fast_read_dword], 8, 15);
413
// we get number of dummy clocks cycles needed, also include mode bits
414
_desc.fast_read_mode_clocks = SFDP_GET_BITS(param_table[fast_read_dword], 5, 7);
415
_desc.fast_read_dummy_cycles = SFDP_GET_BITS(param_table[fast_read_dword], 0, 4);
416
417
if (_desc.fast_read_ins == 0) {
418
Debug("Fast read unsupported");
419
return false;
420
}
421
422
if (!octo_spi) {
423
_desc.wide_mode_enable = SFDP_GET_BITS(param_table[14], 20, 22);
424
if (_desc.wide_mode_enable != 0b000 && _desc.wide_mode_enable != QUAD_ENABLE_B1R2) {
425
Debug("Unsupported Quad Enable Requirement 0x%x", _desc.wide_mode_enable);
426
return false;
427
}
428
if (SFDP_GET_BIT(param_table[14], 4) && _desc.wide_mode_enable != QUAD_ENABLE_B1R2) {
429
Debug("Unsupported Quad Enable Requirement: set QE bits");
430
return false;
431
}
432
}
433
#if HAL_USE_OCTOSPI
434
else {
435
_desc.wide_mode_enable = SFDP_GET_BITS(param_table[18], 20, 22);
436
if (_desc.wide_mode_enable != 0b000 && _desc.wide_mode_enable != OCTO_ENABLE_B3R2) {
437
Debug("Unsupported Octo Enable Requirement 0x%x", _desc.wide_mode_enable);
438
return false;
439
}
440
if (SFDP_GET_BIT(param_table[18], 5) && _desc.wide_mode_enable != OCTO_ENABLE_B3R2) {
441
Debug("Unsupported Quad Enable Requirement: set WREN bits");
442
return false;
443
}
444
}
445
#endif
446
447
// if (!SFDP_GET_BIT(param_table[4], 4)) {
448
// Debug("Quad mode unsupported");
449
// return false;
450
// }
451
452
453
// Configure XIP mode Ref. JESD216D 6.4.18
454
if (SFDP_GET_BIT(param_table[14], 9)) {
455
_desc.is_xip_supported = true;
456
} else {
457
_desc.is_xip_supported = false;
458
}
459
if (_desc.is_xip_supported) {
460
if (SFDP_GET_BIT(param_table[14],16)) {
461
_desc.entry_method = AP_FlashIface_JEDEC::XIP_ENTRY_METHOD_1;
462
} else if (SFDP_GET_BIT(param_table[14],17)) {
463
_desc.entry_method = AP_FlashIface_JEDEC::XIP_ENTRY_METHOD_2;
464
} else {
465
Debug("Unsupported XIP enable sequence 0x%x", uint8_t(SFDP_GET_BITS(param_table[14],16, 19)));
466
}
467
}
468
469
// Configure Status Polling Method Ref. JESD216D 6.4.17
470
if (SFDP_GET_BIT(param_table[13], 3)) {
471
_desc.legacy_status_polling = false;
472
_desc.status_read_ins = 0x70;
473
} else if (SFDP_GET_BIT(param_table[13], 2)) {
474
_desc.legacy_status_polling = true;
475
_desc.status_read_ins = CMD_READ_STATUS_1;
476
}
477
}
478
initialised = true;
479
return true;
480
}
481
482
// Configures device to normal working state, currently 1-4-4 WSPI
483
bool AP_FlashIface_JEDEC::configure_device()
484
{
485
// Enable 1-4-4 mode
486
if (_desc.wide_mode_enable == QUAD_ENABLE_B1R2) {
487
uint8_t reg1 = 0, reg2 = 0;
488
if (!read_reg(CMD_READ_STATUS_1, reg1)) {
489
Debug("Failed reg1 read");
490
return false;
491
}
492
if (!read_reg(CMD_READ_STATUS_2, reg2)) {
493
Debug("Failed reg2 read");
494
return false;
495
}
496
write_enable();
497
wait_ready();
498
499
AP_HAL::WSPIDevice::CommandHeader cmd {
500
.cmd = 0x01,
501
.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
502
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE,
503
.addr = 0,
504
.alt = 0,
505
.dummy = 0
506
};
507
508
reg2 |= 0x2; // enable QE bit
509
uint8_t write_val[2] { reg1, reg2 };
510
_dev->set_cmd_header(cmd);
511
512
if (!_dev->transfer(write_val, 2, nullptr, 0)) {
513
Debug("Failed QE write");
514
write_disable();
515
return false;
516
}
517
518
write_disable();
519
520
if (!read_reg(0x35, reg2) || (reg2 & 0x2) == 0) {
521
Debug("Failed to set QE bit");
522
return false;
523
}
524
525
Debug("Device configured for 1-4-4 mode: QE bit 0x%x, fast read ins/cycles 0x%x/0x%x",
526
_desc.quad_mode_enable, _desc.fast_read_ins, _desc.fast_read_dummy_cycles);
527
528
// Hurray! We are in wide mode
529
_wide_spi_mode = WSPIMode::QuadSPI;
530
}
531
#if HAL_USE_OCTOSPI
532
// Enable 1-8-8 mode
533
else if (_desc.wide_mode_enable == OCTO_ENABLE_B3R2) {
534
uint8_t reg2;
535
536
AP_HAL::WSPIDevice::CommandHeader read_reg {
537
.cmd = 0x65,
538
.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
539
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE |
540
AP_HAL::WSPI::CFG_ADDR_MODE_ONE_LINE |
541
AP_HAL::WSPI::CFG_ADDR_SIZE_8,
542
.addr = 0x02,
543
.alt = 0,
544
.dummy = 8,
545
};
546
547
_dev->set_cmd_header(read_reg);
548
if (!_dev->transfer(nullptr, 0, &reg2, sizeof(reg2))) {
549
Debug("Failed reg2 read");
550
return false;
551
}
552
553
write_enable();
554
wait_ready();
555
556
reg2 |= 0x4; // enable OE bit
557
558
if (!write_reg(0x31, reg2)) {
559
Debug("Failed OE write");
560
write_disable();
561
return false;
562
}
563
564
write_disable();
565
566
_dev->set_cmd_header(read_reg);
567
if (!_dev->transfer(nullptr, 0, &reg2, sizeof(reg2)) || (reg2 & 0x4) == 0) {
568
Debug("Failed to set OE bit");
569
return false;
570
}
571
Debug("Device configured for 1-8-8 mode: OE bit 0x%x, fast read ins/cycles 0x%x/0x%x",
572
_desc.wide_mode_enable, _desc.fast_read_ins, _desc.fast_read_dummy_cycles);
573
574
// Hurray! We are in wide mode
575
_wide_spi_mode = WSPIMode::OctoSPI;
576
}
577
#endif
578
return true;
579
}
580
581
// Enables commands that modify flash data or settings
582
bool AP_FlashIface_JEDEC::write_enable()
583
{
584
if (_desc.write_enable_ins) {
585
wait_ready();
586
write_enable_called = true;
587
return send_cmd(_desc.write_enable_ins);
588
}
589
return true;
590
}
591
592
// Disables commands that modify flash data or settings
593
bool AP_FlashIface_JEDEC::write_disable()
594
{
595
if (_desc.write_enable_ins) {
596
wait_ready();
597
write_enable_called = true;
598
return send_cmd(CMD_WRITE_DISABLE);
599
}
600
return true;
601
}
602
603
// Read modify write register
604
bool AP_FlashIface_JEDEC::modify_reg(uint8_t read_ins, uint8_t write_ins,
605
uint8_t mask, uint8_t val)
606
{
607
// Read
608
uint8_t reg_val;
609
if (!read_reg(read_ins, reg_val)) {
610
return false;
611
}
612
613
// Modify
614
reg_val = (reg_val & ~mask) | (val & mask);
615
616
// Write
617
if (!write_reg(write_ins, reg_val)) {
618
return false;
619
}
620
return true;
621
}
622
623
// reads a register value of chip using instruction
624
bool AP_FlashIface_JEDEC::read_reg(uint8_t read_ins, uint8_t &read_val)
625
{
626
AP_HAL::WSPIDevice::CommandHeader cmd;
627
cmd.cmd = read_ins;
628
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
629
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE;
630
cmd.addr = 0;
631
cmd.alt = 0;
632
cmd.dummy = 0;
633
_dev->set_cmd_header(cmd);
634
if (!_dev->transfer(nullptr, 0, &read_val, sizeof(read_val))) {
635
Debug("Failed Register Read");
636
return false;
637
}
638
return true;
639
}
640
641
// sends instruction to write a register value in the chip
642
bool AP_FlashIface_JEDEC::write_reg(uint8_t write_ins, uint8_t write_val)
643
{
644
AP_HAL::WSPIDevice::CommandHeader cmd;
645
cmd.cmd = write_ins;
646
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
647
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE;
648
cmd.addr = 0;
649
cmd.alt = 0;
650
cmd.dummy = 0;
651
_dev->set_cmd_header(cmd);
652
if (!_dev->transfer(&write_val, 1, nullptr, 0)) {
653
Debug("Failed Register Write");
654
return false;
655
}
656
return true;
657
}
658
659
// Sends WSPI command without data
660
bool AP_FlashIface_JEDEC::send_cmd(uint8_t ins)
661
{
662
AP_HAL::WSPIDevice::CommandHeader cmd;
663
cmd.cmd = ins;
664
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE;
665
cmd.addr = 0;
666
cmd.alt = 0;
667
cmd.dummy = 0;
668
_dev->set_cmd_header(cmd);
669
if (!_dev->transfer(nullptr, 0, nullptr, 0)) {
670
Debug("Failed Register Write");
671
return false;
672
}
673
return true;
674
}
675
676
//////////////////////////////////////////////////////
677
////////////////////PUBLIC METHODS////////////////////
678
//////////////////////////////////////////////////////
679
/**
680
* @details Sends command to erase the entire chips.
681
*
682
* @param[out] delay_ms Time to wait until next is_device_busy call
683
* @param[out] timeout_ms Time by which the erase should have timedout
684
*
685
* @return The operation status.
686
* @retval false if the operation failed.
687
* @retval true if the operation succeeded.
688
*
689
*/
690
bool AP_FlashIface_JEDEC::start_mass_erase(uint32_t &delay_ms, uint32_t &timeout_ms)
691
{
692
write_enable();
693
wait_ready();
694
695
AP_HAL::WSPIDevice::CommandHeader cmd;
696
cmd.cmd = CMD_MASS_ERASE;
697
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE;
698
cmd.addr = 0;
699
cmd.alt = 0;
700
cmd.dummy = 0;
701
_dev->set_cmd_header(cmd);
702
if (!_dev->transfer(nullptr, 0, nullptr, 0)) { // Command only
703
write_disable();
704
Debug("Failed to send erase command");
705
return false;
706
}
707
delay_ms = _desc.mass_erase_delay_ms;
708
timeout_ms = _desc.mass_erase_timeout_ms;
709
write_disable();
710
return true;
711
}
712
713
/**
714
* @details Sends command to erase a sector of the chip.
715
*
716
* @param[in] sector Sector number to be erased
717
* @param[out] delay_ms Time to wait until next is_device_busy call
718
* @param[out] timeout_ms Time by which the erase should have timedout
719
*
720
* @return The operation status.
721
* @retval false if the operation failed.
722
* @retval true if the operation succeeded.
723
*
724
*/
725
bool AP_FlashIface_JEDEC::start_sector_erase(uint32_t sector, uint32_t &delay_ms, uint32_t &timeout_ms)
726
{
727
if (sector > _desc.sector_count) {
728
Debug("Invalid sector");
729
return false;
730
}
731
uint32_t erasing;
732
bool ret = start_erase_offset(_desc.sector_size*sector, _desc.sector_size, erasing, delay_ms, timeout_ms);
733
if (!ret || (erasing != _desc.sector_size)) {
734
Debug("Failed to erase sector");
735
return false;
736
}
737
return true;
738
}
739
740
/**
741
* @details Tries to erase as much as possible starting from the offset
742
* until size. User needs to call this as many times as needed
743
* taking already erased bytes into account, until desired erase
744
* has taken place
745
*
746
* @param[in] offset address offset for erase
747
* @param[in] size size desired to be erased
748
* @param[out] erasing number of bytes erasing
749
* @param[out] delay_ms Time to wait until next is_device_busy call
750
* @param[out] timeout_ms Time by which the erase should have timedout
751
*
752
* @return The operation status.
753
* @retval false if the operation failed.
754
* @retval true if the operation succeeded.
755
*
756
*/
757
bool AP_FlashIface_JEDEC::start_erase_offset(uint32_t offset, uint32_t size, uint32_t &erasing,
758
uint32_t &delay_ms, uint32_t &timeout_ms)
759
{
760
uint8_t ins = 0;
761
uint32_t erase_size = 0;
762
erasing = 0;
763
// Find the maximum size we can erase
764
for (uint8_t i=0; i < 4; i++) {
765
if (_desc.erase_type[i].size == 0) {
766
continue;
767
}
768
if (_desc.erase_type[i].size < erase_size) {
769
// we already found a larger size we can erase
770
continue;
771
}
772
// check if we can find an instruction to match the erase req.
773
if ((size >= _desc.erase_type[i].size) && !(offset % _desc.erase_type[i].size)) {
774
erase_size = size;
775
ins = _desc.erase_type[i].ins;
776
delay_ms = _desc.erase_type[i].delay_ms;
777
timeout_ms = _desc.erase_type[i].timeout_ms;
778
}
779
}
780
if (erase_size == 0) {
781
Debug("Requested Erase size is too small");
782
return false;
783
}
784
if ((offset+erase_size) > _desc.flash_size) {
785
Debug("Requested erase overflows supported flash size");
786
return false;
787
}
788
// Start Erasing
789
write_enable();
790
wait_ready();
791
792
AP_HAL::WSPIDevice::CommandHeader cmd;
793
cmd.cmd = ins;
794
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
795
AP_HAL::WSPI::CFG_ADDR_MODE_ONE_LINE |
796
AP_HAL::WSPI::CFG_ADDR_SIZE_24;
797
cmd.addr = offset;
798
cmd.alt = 0;
799
cmd.dummy = 0;
800
_dev->set_cmd_header(cmd);
801
if (!_dev->transfer(nullptr, 0, nullptr, 0)) { // Command only
802
write_disable();
803
Debug("Failed to send erase command");
804
return false;
805
}
806
write_disable();
807
erasing = erase_size;
808
return true;
809
}
810
811
812
/**
813
* @details Check if selected sector is erased.
814
*
815
* @param[in] sector sector for which to check erase
816
* @return The operation status.
817
* @retval false if the operation failed.
818
* @retval true if the operation succeeded.
819
*
820
*/
821
bool AP_FlashIface_JEDEC::verify_sector_erase(uint32_t sector)
822
{
823
uint8_t buf[MAX_READ_SIZE] {}; // Read 1KB per read
824
for (uint32_t offset = _desc.sector_size*sector; offset < (_desc.sector_size*(sector+1)); offset+=sizeof(buf)) {
825
if (read(offset, buf, sizeof(buf))) {
826
for (uint16_t i = 0; i < sizeof(buf); i++) {
827
if (buf[i] != 0xFF) {
828
Debug("Found unerased byte %x @ offset %ld", (unsigned int)buf[i], (unsigned long)offset);
829
return false;
830
}
831
}
832
} else {
833
Debug("Read Failed");
834
return false;
835
}
836
}
837
return true;
838
}
839
840
/**
841
* @details Sends command to start programming a page of the chip.
842
*
843
* @param[in] page Page number to be written to
844
* @param[in] data data to be written
845
* @param[out] delay_us Time to wait until next is_device_busy call
846
* @param[out] timeout_us Time after which the erase should be timedout,
847
* should be reset at every call.
848
* @return The operation status.
849
* @retval false if the operation failed.
850
* @retval true if the operation succeeded.
851
*
852
*/
853
bool AP_FlashIface_JEDEC::start_program_page(uint32_t page, const uint8_t* data,
854
uint32_t &delay_us, uint32_t &timeout_us)
855
{
856
if (page > _desc.page_count) {
857
Debug("Invalid Page");
858
return false;
859
}
860
uint32_t programming;
861
bool ret = start_program_offset(_desc.page_size*page, data, _desc.sector_size, programming, delay_us, timeout_us);
862
if (!ret || (programming != _desc.page_size)) {
863
Debug("Failed to program page");
864
return false;
865
}
866
return true;
867
}
868
869
/**
870
* @details Tries to program as much as possible starting from the offset
871
* until size. User needs to call this as many times as needed
872
* taking already programmed bytes into account.
873
*
874
* @param[in] offset address offset for program
875
* @param[in] data data to be programmed
876
* @param[in] size size desired to be programmed
877
* @param[out] programming number of bytes programming, taking care of the limits
878
* @param[out] delay_us Time to wait until program typically finishes
879
* @param[out] timeout_us Time by which current program should have timedout.
880
* @return The operation status.
881
* @retval false if the operation failed.
882
* @retval true if the operation succeeded.
883
*
884
*/
885
bool AP_FlashIface_JEDEC::start_program_offset(uint32_t offset, const uint8_t* data, uint32_t size, uint32_t &programming,
886
uint32_t &delay_us, uint32_t &timeout_us)
887
{
888
if (size > _desc.page_size) {
889
// we can only program single
890
// page at the max in one go
891
size = _desc.page_size;
892
}
893
// Ensure we don't go beyond the page of offset, while writing
894
size = MIN(_desc.page_size - (offset % _desc.page_size), size);
895
896
write_enable();
897
wait_ready();
898
899
AP_HAL::WSPIDevice::CommandHeader cmd;
900
cmd.cmd = CMD_PAGE_PROGRAM;
901
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
902
AP_HAL::WSPI::CFG_ADDR_MODE_ONE_LINE |
903
AP_HAL::WSPI::CFG_ADDR_SIZE_24 |
904
AP_HAL::WSPI::CFG_DATA_MODE_ONE_LINE;
905
cmd.addr = offset;
906
cmd.alt = 0;
907
cmd.dummy = 0;
908
_dev->set_cmd_header(cmd);
909
if (!_dev->transfer(data, size, nullptr, 0)) { // Command only
910
write_disable();
911
Debug("Failed to send program command");
912
return false;
913
}
914
write_disable();
915
programming = size;
916
// we are mostly going to program in chunks so this will do
917
delay_us = (_desc.page_prog_delay_us*size)/(_desc.page_size);
918
timeout_us = (_desc.page_prog_timeout_us*size)/(_desc.page_size);
919
return true;
920
}
921
922
/**
923
* @details Read data from flash chip.
924
*
925
* @param[in] offset address offset from where to start the read
926
* @param[out] data data to be read from the device
927
* @param[in] size size of the data to be read
928
* @return The operation status.
929
* @retval false if the operation failed.
930
* @retval true if the operation succeeded.
931
*
932
*/
933
bool AP_FlashIface_JEDEC::read(uint32_t offset, uint8_t* data, uint32_t size)
934
{
935
if ((offset + size) > _desc.flash_size) {
936
// reading more than what exists
937
return false;
938
}
939
940
wait_ready();
941
942
uint32_t read_ptr, read_size;
943
for (read_ptr = offset; read_ptr < (offset+size); read_ptr+=MAX_READ_SIZE) {
944
read_size = MIN((offset+size) - read_ptr, MAX_READ_SIZE);
945
AP_HAL::WSPIDevice::CommandHeader cmd;
946
cmd.cmd = _desc.fast_read_ins;
947
cmd.addr = read_ptr;
948
cmd.alt = 0;
949
cmd.cfg = AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
950
AP_HAL::WSPI::CFG_ADDR_SIZE_24 |
951
AP_HAL::WSPI::CFG_ALT_SIZE_8;
952
if (_wide_spi_mode == WSPIMode::QuadSPI) {
953
cmd.cfg |= (AP_HAL::WSPI::CFG_ADDR_MODE_FOUR_LINES |
954
AP_HAL::WSPI::CFG_DATA_MODE_FOUR_LINES |
955
AP_HAL::WSPI::CFG_ALT_MODE_FOUR_LINES);
956
#if HAL_USE_OCTOSPI
957
} else if (_wide_spi_mode == WSPIMode::OctoSPI) {
958
cmd.cfg |= (AP_HAL::WSPI::CFG_ADDR_MODE_EIGHT_LINES |
959
AP_HAL::WSPI::CFG_DATA_MODE_EIGHT_LINES |
960
AP_HAL::WSPI::CFG_ALT_MODE_EIGHT_LINES);
961
#endif
962
}
963
964
if (_desc.fast_read_mode_clocks == 1){
965
cmd.dummy = _desc.fast_read_dummy_cycles - 1;
966
} else {
967
cmd.dummy = _desc.fast_read_dummy_cycles;
968
}
969
_dev->set_cmd_header(cmd);
970
if (!_dev->transfer(nullptr, 0, &data[read_ptr-offset], read_size)) { // Command only
971
Debug("Failed to read flash");
972
return false;
973
}
974
}
975
return true;
976
}
977
978
/**
979
* @details Check if the device is busy.
980
*
981
* @return device busy with last op.
982
*
983
* @retval false if the device is ready.
984
* @retval true if the device is busy.
985
*
986
*/
987
bool AP_FlashIface_JEDEC::is_device_busy()
988
{
989
// wait for peripheral to become free
990
while (_dev->is_busy()) {}
991
992
uint8_t status;
993
read_reg(_desc.status_read_ins, status);
994
995
if (_desc.legacy_status_polling) {
996
return (status & 0x1);
997
} else {
998
return !(status & 1<<7);
999
}
1000
}
1001
1002
// wait for the chip to be ready for the next instruction
1003
void AP_FlashIface_JEDEC::wait_ready()
1004
{
1005
while (is_device_busy()) {
1006
}
1007
}
1008
1009
/**
1010
* @details Starts execution in place mode
1011
*
1012
* @return if successfully entered XIP mode.
1013
*
1014
* @retval false the device failed to enter XIP mode.
1015
* @retval true the device has entered XIP mode.
1016
*
1017
*/
1018
bool AP_FlashIface_JEDEC::start_xip_mode(void** addr)
1019
{
1020
wait_ready();
1021
1022
if (!_desc.is_xip_supported) {
1023
Debug("XIP mode unsupported on this chip");
1024
return false;
1025
}
1026
1027
bool success = false;
1028
1029
switch(_desc.entry_method) {
1030
case AP_FlashIface_JEDEC::XIP_ENTRY_METHOD_1:
1031
{
1032
// Set WSPI module for XIP mode
1033
AP_HAL::WSPIDevice::CommandHeader cmd;
1034
cmd.cmd = _desc.fast_read_ins; // generally 0xEB for 1-4-4 access
1035
cmd.alt = 0xF0; // add M0-7 bits in alt to make up 32-bit address phase, sec 8.2.11 W25Q64JV reference
1036
cmd.cfg = AP_HAL::WSPI::CFG_ADDR_SIZE_24 |
1037
AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
1038
AP_HAL::WSPI::CFG_ALT_SIZE_8;
1039
if (_wide_spi_mode == WSPIMode::QuadSPI) {
1040
cmd.cfg |= (AP_HAL::WSPI::CFG_ADDR_MODE_FOUR_LINES |
1041
AP_HAL::WSPI::CFG_DATA_MODE_FOUR_LINES |
1042
AP_HAL::WSPI::CFG_ALT_MODE_FOUR_LINES);
1043
#if HAL_USE_OCTOSPI
1044
} else if (_wide_spi_mode == WSPIMode::OctoSPI) {
1045
cmd.cfg |= (AP_HAL::WSPI::CFG_ADDR_MODE_EIGHT_LINES |
1046
AP_HAL::WSPI::CFG_DATA_MODE_EIGHT_LINES |
1047
AP_HAL::WSPI::CFG_ALT_MODE_EIGHT_LINES);
1048
#endif
1049
}
1050
cmd.addr = 0;
1051
cmd.dummy = _desc.fast_read_dummy_cycles;
1052
_dev->set_cmd_header(cmd);
1053
success = _dev->enter_xip_mode(addr);
1054
break;
1055
}
1056
case AP_FlashIface_JEDEC::XIP_ENTRY_METHOD_2:
1057
{
1058
// set configuration register to start 0-4-4 mode
1059
write_enable();
1060
wait_ready();
1061
1062
if (!modify_reg(0x85, 0x81, 1<<3, 0)) {
1063
Debug("Failed to configure chip for XIP");
1064
write_disable();
1065
return false;
1066
}
1067
// Set WSPI module for XIP mode
1068
AP_HAL::WSPIDevice::CommandHeader cmd;
1069
cmd.cmd = _desc.fast_read_ins;
1070
cmd.alt = 0;
1071
cmd.cfg = AP_HAL::WSPI::CFG_ADDR_SIZE_24 |
1072
AP_HAL::WSPI::CFG_CMD_MODE_ONE_LINE |
1073
AP_HAL::WSPI::CFG_ALT_SIZE_8 |
1074
AP_HAL::WSPI::CFG_SIOO;
1075
if (_wide_spi_mode == WSPIMode::QuadSPI) {
1076
cmd.cfg |= (AP_HAL::WSPI::CFG_ADDR_MODE_FOUR_LINES |
1077
AP_HAL::WSPI::CFG_DATA_MODE_FOUR_LINES |
1078
AP_HAL::WSPI::CFG_ALT_MODE_FOUR_LINES);
1079
#if HAL_USE_OCTOSPI
1080
} else if (_wide_spi_mode == WSPIMode::OctoSPI) {
1081
cmd.cfg |= (AP_HAL::WSPI::CFG_ADDR_MODE_EIGHT_LINES |
1082
AP_HAL::WSPI::CFG_DATA_MODE_EIGHT_LINES |
1083
AP_HAL::WSPI::CFG_ALT_MODE_EIGHT_LINES);
1084
#endif
1085
}
1086
cmd.addr = 0;
1087
// correct dummy bytes because of addition of alt bytes
1088
cmd.dummy = _desc.fast_read_dummy_cycles - 1;
1089
_dev->set_cmd_header(cmd);
1090
success = _dev->enter_xip_mode(addr);
1091
break;
1092
}
1093
default:
1094
{
1095
Debug("Unsupported XIP Entry Method");
1096
return false;
1097
}
1098
}
1099
// make sure that the flash is ready once we enter XIP
1100
DELAY_MICROS(100);
1101
return success;
1102
}
1103
1104
bool AP_FlashIface_JEDEC::stop_xip_mode()
1105
{
1106
return _dev->exit_xip_mode();
1107
}
1108
1109