Skip to content

Commit f23fc16

Browse files
committed
bd: Added the MX25RBlockDevice
Supports MX25R series NOR SPI flash devices. Based off: https://developer.mbed.org/users/alec1/code/SPI_MX25R/
1 parent eed9b2a commit f23fc16

File tree

3 files changed

+499
-0
lines changed

3 files changed

+499
-0
lines changed
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2016 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "MX25RBlockDevice.h"
18+
19+
// Read/write/erase sizes
20+
#define MX25R_READ_SIZE 1
21+
#define MX25R_PROGRAM_SIZE 256
22+
#define MX25R_ERASE_SIZE1 4096
23+
#define MX25R_ERASE_SIZE2 32768
24+
#define MX25R_ERASE_SIZE3 65536
25+
26+
#define MX25R_TIMEOUT 10000
27+
28+
// MX25R RDSR definitions
29+
enum mx25r_rdsr {
30+
MX25R_WEL = 0x2,
31+
MX25R_WIP = 0x1,
32+
};
33+
34+
// MX25R Series Register Command Table.
35+
enum mx25r_cmd {
36+
MX25R_READ = 0x03, // x1 Normal Read Data Byte
37+
MX25R_FREAD = 0x0b, // x1 Fast Read Data Byte
38+
MX25R_2READ = 0xbb, // x2 2READ
39+
MX25R_DREAD = 0x3b, // x2 DREAD
40+
MX25R_4READ = 0xeb, // x4 4READ
41+
MX25R_QREAD = 0x6b, // x4 QREAD
42+
MX25R_PP = 0x02, // Page Program
43+
MX25R_4PP = 0x38, // x4 PP
44+
MX25R_SE = 0x20, // 4KB Sector Erase
45+
MX25R_32KBE = 0x52, // 32KB Block Erase
46+
MX25R_BE = 0xd8, // 64KB Block Erase
47+
MX25R_CE = 0xc7, // Chip Erase
48+
MX25R_RDSFDP = 0x5a, // Read SFDP
49+
MX25R_WREN = 0x06, // Write Enable
50+
MX25R_WRDI = 0x04, // Write Disable
51+
MX25R_RDSR = 0x05, // Read Status Register
52+
MX25R_RDCR = 0x15, // Read Configuration Register
53+
MX25R_WRSR = 0x01, // Write Status Register
54+
MX25R_PESUS = 0xb0, // Program/Erase Suspend
55+
MX25R_PERES = 0x30, // Program/Erase Resume
56+
MX25R_DP = 0xb9, // Enter Deep Power Down
57+
MX25R_SBL = 0xc0, // Set Burst Length
58+
MX25R_RDID = 0x9f, // Read Manufacturer and JDEC Device ID
59+
MX25R_REMS = 0x90, // Read Electronic Manufacturer and Device ID
60+
MX25R_RES = 0xab, // Read Electronic ID
61+
MX25R_ENSO = 0xb1, // Enter Secure OTP
62+
MX25R_EXSO = 0xc1, // Exit Secure OTP
63+
MX25R_RDSCUR = 0x2b, // Read Security Register
64+
MX25R_WRSCUR = 0x2f, // Write Security Register
65+
MX25R_NOP = 0x00, // No Operation
66+
MX25R_RSTEN = 0x66, // Reset Enable
67+
MX25R_RST = 0x99, // Reset
68+
MX25R_RRE = 0xff, // Release Read Enhanced Mode
69+
};
70+
71+
72+
MX25RBlockDevice::MX25RBlockDevice(PinName mosi, PinName miso, PinName sclk, PinName cs)
73+
: _spi(mosi, miso, sclk), _cs(cs), _size(0)
74+
{
75+
}
76+
77+
bd_error_t MX25RBlockDevice::init()
78+
{
79+
bd_error_t err = _sync();
80+
if (err) {
81+
return err;
82+
}
83+
84+
// Find size from device ID
85+
uint8_t id[3];
86+
87+
_cs = 0;
88+
_spi.write(MX25R_RDID);
89+
for (uint32_t i = 0; i < 3; i++) {
90+
id[i] = _spi.write(0);
91+
}
92+
_cs = 1;
93+
94+
// Count in bits is stored as power of 2 in BCD
95+
_size = 1ULL << ((id[1] >> 4)*10 + (0xf & id[0]) - 3);
96+
97+
return 0;
98+
}
99+
100+
bd_error_t MX25RBlockDevice::deinit()
101+
{
102+
return 0;
103+
}
104+
105+
bd_error_t MX25RBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
106+
{
107+
// Check the address and size fit onto the chip.
108+
if (!is_valid_read(addr, size)) {
109+
return BD_ERROR_PARAMETER;
110+
}
111+
112+
_cs = 0;
113+
_spi.write(MX25R_FREAD);
114+
_spi.write((char)(0xff & (addr >> 16)));
115+
_spi.write((char)(0xff & (addr >> 8 )));
116+
_spi.write((char)(0xff & (addr >> 0 )));
117+
_spi.write(0);
118+
119+
for (bd_size_t i = 0; i < size; i++) {
120+
static_cast<uint8_t*>(buffer)[i] = _spi.write(0);
121+
}
122+
_cs = 1;
123+
124+
return 0;
125+
}
126+
127+
bd_error_t MX25RBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
128+
{
129+
// Check the address and size fit onto the chip.
130+
if (!is_valid_program(addr, size)) {
131+
return BD_ERROR_PARAMETER;
132+
}
133+
134+
for (bd_size_t page = 0; page < size; page += MX25R_PROGRAM_SIZE) {
135+
bd_error_t err = _wren();
136+
if (err) {
137+
return err;
138+
}
139+
140+
// Write 256 byte pages
141+
_cs = 0;
142+
_spi.write(MX25R_PP);
143+
_spi.write((char)(0xff & ((addr+page) >> 16)));
144+
_spi.write((char)(0xff & ((addr+page) >> 8 )));
145+
_spi.write((char)(0xff & ((addr+page) >> 0 )));
146+
147+
for (uint32_t i = 0; i < MX25R_PROGRAM_SIZE; i++) {
148+
_spi.write(static_cast<const uint8_t*>(buffer)[page+i]);
149+
}
150+
_cs = 1;
151+
152+
err = _sync();
153+
if (err) {
154+
return err;
155+
}
156+
}
157+
158+
return 0;
159+
}
160+
161+
bd_error_t MX25RBlockDevice::erase(bd_addr_t addr, bd_size_t size)
162+
{
163+
// Check the address and size fit onto the chip.
164+
if (!is_valid_erase(addr, size)) {
165+
return BD_ERROR_PARAMETER;
166+
}
167+
168+
while (size > 0) {
169+
bd_error_t err = _wren();
170+
if (err) {
171+
return err;
172+
}
173+
174+
bd_size_t chunk;
175+
if (size >= MX25R_ERASE_SIZE3 && !(addr & (MX25R_ERASE_SIZE3 - 1))) {
176+
// Erase a 64k block
177+
_cs = 0;
178+
_spi.write(MX25R_BE);
179+
_spi.write((char)(0xff & (addr >> 16)));
180+
_spi.write((char)(0xff & (addr >> 8 )));
181+
_spi.write((char)(0xff & (addr >> 0 )));
182+
_cs = 1;
183+
184+
chunk = MX25R_ERASE_SIZE3;
185+
} else if (size >= MX25R_ERASE_SIZE2 && !(addr & (MX25R_ERASE_SIZE2 - 1))) {
186+
// Erase a 32k block
187+
_cs = 0;
188+
_spi.write(MX25R_32KBE);
189+
_spi.write((char)(0xff & (addr >> 16)));
190+
_spi.write((char)(0xff & (addr >> 8 )));
191+
_spi.write((char)(0xff & (addr >> 0 )));
192+
_cs = 1;
193+
194+
chunk = MX25R_ERASE_SIZE2;
195+
} else if (size >= MX25R_ERASE_SIZE1 && !(addr & (MX25R_ERASE_SIZE1 - 1))) {
196+
// Erase a 4k block
197+
_cs = 0;
198+
_spi.write(MX25R_SE);
199+
_spi.write((char)(0xff & (addr >> 16)));
200+
_spi.write((char)(0xff & (addr >> 8 )));
201+
_spi.write((char)(0xff & (addr >> 0 )));
202+
_cs = 1;
203+
204+
chunk = MX25R_ERASE_SIZE1;
205+
} else {
206+
MBED_UNREACHABLE;
207+
}
208+
209+
err = _sync();
210+
if (err) {
211+
return err;
212+
}
213+
214+
addr += chunk;
215+
size -= chunk;
216+
}
217+
218+
return 0;
219+
}
220+
221+
bd_error_t MX25RBlockDevice::_wren()
222+
{
223+
_cs = 0;
224+
_spi.write(MX25R_WREN);
225+
_cs = 1;
226+
227+
for (int i = 0; i < MX25R_TIMEOUT; i++) {
228+
// Read status register until write not-in-progress
229+
_cs = 0;
230+
_spi.write(MX25R_RDSR);
231+
uint8_t status = _spi.write(0);
232+
_cs = 1;
233+
234+
// Check WEL bit
235+
if (status & MX25R_WEL) {
236+
return 0;
237+
}
238+
239+
wait_ms(1);
240+
}
241+
242+
return BD_ERROR_DEVICE_ERROR;
243+
}
244+
245+
bd_error_t MX25RBlockDevice::_sync()
246+
{
247+
for (int i = 0; i < MX25R_TIMEOUT; i++) {
248+
// Read status register until write not-in-progress
249+
_cs = 0;
250+
_spi.write(MX25R_RDSR);
251+
uint8_t status = _spi.write(0);
252+
_cs = 1;
253+
254+
// Check WIP bit
255+
if (!(status & MX25R_WIP)) {
256+
return 0;
257+
}
258+
259+
wait_ms(1);
260+
}
261+
262+
return BD_ERROR_DEVICE_ERROR;
263+
}
264+
265+
bd_size_t MX25RBlockDevice::read_size()
266+
{
267+
return MX25R_READ_SIZE;
268+
}
269+
270+
bd_size_t MX25RBlockDevice::program_size()
271+
{
272+
return MX25R_PROGRAM_SIZE;
273+
}
274+
275+
bd_size_t MX25RBlockDevice::erase_size()
276+
{
277+
return MX25R_ERASE_SIZE1;
278+
}
279+
280+
bd_size_t MX25RBlockDevice::size()
281+
{
282+
return _size;
283+
}

0 commit comments

Comments
 (0)