mrfioc2  2.3.0
Classes | Public Member Functions | List of all members
mrf::CFIFlash Class Reference

Handling for Common Flash Interfafce compliant chips. More...

#include <flash.h>

Classes

struct  ID
 

Public Member Functions

 CFIFlash (const SPIDevice &dev)
 
 ~CFIFlash ()
 
void readID (ID *id)
 execute command 0x9f JEDEC-ID read More...
 
bool writable ()
 
epicsUInt32 alignement ()
 
epicsUInt32 blockSize ()
 
epicsUInt32 pageSize ()
 
epicsUInt32 sectorSize ()
 
void read (epicsUInt32 start, epicsUInt32 count, epicsUInt8 *in)
 
void read (epicsUInt32 start, std::vector< epicsUInt8 > &in)
 
void write (epicsUInt32 start, epicsUInt32 count, const epicsUInt8 *out, bool strict=true)
 
void write (epicsUInt32 start, const std::vector< epicsUInt8 > &out, bool strict=true)
 
void erase (epicsUInt32 start, epicsUInt32 count, bool strict=true)
 

Detailed Description

Handling for Common Flash Interfafce compliant chips.

Definition at line 23 of file flash.h.

Constructor & Destructor Documentation

◆ CFIFlash()

mrf::CFIFlash::CFIFlash ( const SPIDevice dev)
explicit

Definition at line 25 of file flash.cpp.

26  :dev(dev)
27  ,haveinfo(false)
28 {}

◆ ~CFIFlash()

mrf::CFIFlash::~CFIFlash ( )

Definition at line 30 of file flash.cpp.

30 {}

Member Function Documentation

◆ alignement()

epicsUInt32 mrf::CFIFlash::alignement ( )
inline

Definition at line 50 of file flash.h.

50 { check(); return (info.pageSize-1)|(info.sectorSize-1); }
epicsUInt32 pageSize
PAGE PROGRAM (0x02) size in bytes. Always a power of 2.
Definition: flash.h:38
epicsUInt32 sectorSize
SECTOR ERASE (0xd8) size in bytes. Always a power of 2.
Definition: flash.h:38

◆ blockSize()

epicsUInt32 mrf::CFIFlash::blockSize ( )
inline

Definition at line 52 of file flash.h.

52 { return alignement()+1u; }
epicsUInt32 alignement()
Definition: flash.h:50

◆ erase()

void mrf::CFIFlash::erase ( epicsUInt32  start,
epicsUInt32  count,
bool  strict = true 
)

Definition at line 274 of file flash.cpp.

275 {
276  if((start&0xff000000) || (count&0xff000000) || ((start+count)&0xff000000))
277  std::runtime_error("start/count exceeds 24-bit addressing");
278 
279  check();
280 
281  if(strict && info.capacity==0)
282  throw std::runtime_error("Won't attempt to write when capacity isn't known");
283 
284  else if(start>=info.capacity || (start+count)>info.capacity)
285  throw std::runtime_error("Can't write beyond capacity");
286 
287  if(info.pageSize==0 || info.sectorSize==0)
288  throw std::runtime_error("Won't attempt to write to unsupported flash chip");
289 
290  {
291  epicsUInt32 mask = (info.pageSize-1u) | (info.sectorSize-1u);
292  if(start&mask)
293  throw std::runtime_error("start address not aligned to page & sector sizes");
294 
295  if(strict && ((start+count)&mask))
296  throw std::runtime_error("end address not aligned to page & sector sizes");
297  }
298 
299  const epicsUInt32 end = start+count;
300 
301  const double timeout = dev.interface()->timeout();
302 
303  WriteEnabler WE(*this);
304 
305  // erase necessary sectors
306 
307  for(epicsUInt32 addr=start; addr<end; addr+=info.sectorSize)
308  {
309  busyWait(timeout);
310 
311  WE.enable();
312 
313  epicsUInt8 cmd[4];
314  cmd[0] = 0xd8; // SECTOR ERASE
315  cmd[1] = (addr>>16)&0xff;
316  cmd[2] = (addr>> 8)&0xff;
317  cmd[3] = (addr>> 0)&0xff;
318  SPIInterface::Operation op = {4, cmd, NULL};
319 
320  {
321  SPIDevice::Selector S(dev);
322  dev.interface()->cycles(1, &op);
323  }
324  }
325 }
epicsUInt32 pageSize
PAGE PROGRAM (0x02) size in bytes. Always a power of 2.
Definition: flash.h:38
double timeout() const
timeout in seconds for an individual cycle()
Definition: spi.cpp:41
virtual void cycles(size_t nops, const Operation *ops)
Definition: spi.cpp:25
epicsUInt32 capacity
total capacity in bytes
Definition: flash.h:38
epicsUInt32 sectorSize
SECTOR ERASE (0xd8) size in bytes. Always a power of 2.
Definition: flash.h:38
Definition: devObj.h:97
SPIInterface * interface() const
Definition: spi.h:59

◆ pageSize()

epicsUInt32 mrf::CFIFlash::pageSize ( )
inline

Definition at line 53 of file flash.h.

53 { check(); return info.pageSize; }
epicsUInt32 pageSize
PAGE PROGRAM (0x02) size in bytes. Always a power of 2.
Definition: flash.h:38

◆ read() [1/2]

void mrf::CFIFlash::read ( epicsUInt32  start,
epicsUInt32  count,
epicsUInt8 *  in 
)

Definition at line 124 of file flash.cpp.

125 {
126  if((start&0xff000000) || (count&0xff000000) || ((start+count)&0xff000000))
127  std::runtime_error("start/count exceeds 24-bit addressing");
128 
129  check();
130 
131  epicsUInt8 cmd[5];
132 
133  // as we don't control clock speed, assume support for "fast" read
134  // w/ dummy byte (wait state) after 24-bit address
135  cmd[0] = 0x0b;
136  cmd[1] = (start>>16)&0xff;
137  cmd[2] = (start>> 8)&0xff;
138  cmd[3] = (start>> 0)&0xff;
139  cmd[4] = 0; // dummy
140 
141  SPIInterface::Operation ops[2];
142 
143  ops[0].ncycles = 5;
144  ops[0].out = NULL;
145  ops[0].in = cmd;
146 
147  ops[1].ncycles = count;
148  ops[1].out = data;
149  ops[1].in = NULL;
150 
151  {
152  SPIDevice::Selector S(dev);
153  dev.interface()->cycles(2, ops);
154  }
155 }
virtual void cycles(size_t nops, const Operation *ops)
Definition: spi.cpp:25
SPIInterface * interface() const
Definition: spi.h:59

◆ read() [2/2]

void mrf::CFIFlash::read ( epicsUInt32  start,
std::vector< epicsUInt8 > &  in 
)
inline

Definition at line 57 of file flash.h.

58  { read(start, in.size(), &in[0]); }
void read(epicsUInt32 start, epicsUInt32 count, epicsUInt8 *in)
Definition: flash.cpp:124

◆ readID()

void mrf::CFIFlash::readID ( ID id)

execute command 0x9f JEDEC-ID read

Definition at line 33 of file flash.cpp.

34 {
35  epicsUInt8 cmd[7] = {0x9f, 0u, 0u, 0u},
36  response[7];
37  SPIInterface::Operation ops[2] = {{4, cmd, response}};
38  ops[0].ncycles = 4;
39  ops[0].in = cmd;
40  ops[0].out = response;
41 
42  {
43  SPIDevice::Selector S(dev);
44  dev.interface()->cycles(1, ops);
45  }
46 
47  if(response[1]==0xff)
48  {
49  /* the first read after power up seems to fail.
50  * Presumably some missing initializtion on my part.
51  * A single re-try.
52  */
53  SPIDevice::Selector S(dev);
54  dev.interface()->cycles(1, ops);
55  }
56 
57  id->vendor = response[1];
58  id->dev_type = response[2];
59  id->dev_id = response[3];
60 
61  id->vendorName = "<Unknown>";
62  id->capacity = id->sectorSize = id->pageSize = 0u;
63 
64  if(id->vendor==0x20) { // Micron
65  /* Some Micron parts support the Serial Flash Discoverable Parameter (SFDP) spec.
66  * using command 0x5a (see tech note TN-25-06).
67  * However, so far there isn't anything so interesting.
68  */
69  id->vendorName = "Micron";
70 
71  switch(id->dev_type) {
72  case 0x20: // m25p (Numonyx)
73  id->capacity = 1u<<(id->dev_id);
74  id->sectorSize = 256*1024u; // 2Mbit
75  id->pageSize = 256;
76  break;
77  case 0xba: // mt25q
78  case 0xbb:
79  id->capacity = 1u<<(id->dev_id);
80  id->sectorSize = 64*1024u;
81  id->pageSize = 256;
82  break;
83  }
84 
85  /* Micron puts some extra info after the regular 0x9f payload,
86  * including a serial number.
87  * Byte 4 is the length of the additional payload
88  */
89  ops[0].ncycles = 5;
90 
91  {
92  SPIDevice::Selector S(dev);
93  dev.interface()->cycles(1, ops);
94  }
95 
96  if(response[4]>2) {
97  ops[0].ncycles = 7;
98 
99  id->SN.resize(response[4]-2);
100  ops[1].ncycles = id->SN.size();
101  ops[1].in = NULL;
102  ops[1].out = &id->SN[0];
103 
104  SPIDevice::Selector S(dev);
105  dev.interface()->cycles(2, ops);
106 
107  // if this byte isn't 0, then the spec isn't being followed
108  if(response[6]!=0)
109  id->SN.clear();
110 
111  if((response[5]&0x3)!=0) {
112  // sector size not known
113  id->sectorSize = 0;
114  }
115  }
116  }
117 
118  // we only use 24-bit read/write/erase ops
119  // so capacity beyond 16MB is not accessible.
120  if(id->capacity>0x1000000)
121  id->capacity = 0x1000000;
122 }
virtual void cycles(size_t nops, const Operation *ops)
Definition: spi.cpp:25
SPIInterface * interface() const
Definition: spi.h:59

◆ sectorSize()

epicsUInt32 mrf::CFIFlash::sectorSize ( )
inline

Definition at line 54 of file flash.h.

54 { check(); return info.sectorSize; }
epicsUInt32 sectorSize
SECTOR ERASE (0xd8) size in bytes. Always a power of 2.
Definition: flash.h:38

◆ writable()

bool mrf::CFIFlash::writable ( )
inline

Definition at line 48 of file flash.h.

48 { check(); return info.pageSize>0 && info.sectorSize>0; }
epicsUInt32 pageSize
PAGE PROGRAM (0x02) size in bytes. Always a power of 2.
Definition: flash.h:38
epicsUInt32 sectorSize
SECTOR ERASE (0xd8) size in bytes. Always a power of 2.
Definition: flash.h:38

◆ write() [1/2]

void mrf::CFIFlash::write ( epicsUInt32  start,
epicsUInt32  count,
const epicsUInt8 *  out,
bool  strict = true 
)

Definition at line 157 of file flash.cpp.

161 {
162  if((start&0xff000000) || (count&0xff000000) || ((start+count)&0xff000000))
163  std::runtime_error("start/count exceeds 24-bit addressing");
164 
165  check();
166 
167  if(strict && info.capacity==0)
168  throw std::runtime_error("Won't attempt to write when capacity isn't known");
169 
170  else if(start>=info.capacity || (start+count)>info.capacity)
171  throw std::runtime_error("Can't write beyond capacity");
172 
173  if(info.pageSize==0 || info.sectorSize==0)
174  throw std::runtime_error("Won't attempt to write to unsupported flash chip");
175 
176  {
177  epicsUInt32 mask = (info.pageSize-1u) | (info.sectorSize-1u);
178  if(start&mask)
179  throw std::runtime_error("start address not aligned to page & sector sizes");
180 
181  if(strict && ((start+count)&mask))
182  throw std::runtime_error("end address not aligned to page & sector sizes");
183  }
184 
185  const epicsUInt32 end = start+count;
186 
187  const double timeout = dev.interface()->timeout();
188 
189  {
190  WriteEnabler WE(*this);
191 
192  // erase necessary sectors
193 
194  for(epicsUInt32 addr=start; addr<end; addr+=info.sectorSize)
195  {
196  busyWait(timeout);
197 
198  WE.enable();
199 
200  epicsUInt8 cmd[4];
201  cmd[0] = 0xd8; // SECTOR ERASE
202  cmd[1] = (addr>>16)&0xff;
203  cmd[2] = (addr>> 8)&0xff;
204  cmd[3] = (addr>> 0)&0xff;
205  SPIInterface::Operation op = {4, cmd, NULL};
206 
207  {
208  SPIDevice::Selector S(dev);
209  dev.interface()->cycles(1, &op);
210  }
211  }
212 
213  // program all pages
214 
215  const epicsUInt8 *cur = data;
216  for(epicsUInt32 addr=start; addr<end; addr+=info.pageSize, cur+=info.pageSize)
217  {
218  busyWait(timeout);
219 
220  WE.enable();
221 
222  const epicsUInt32 N = std::min(info.pageSize, end-addr);
223 
224  epicsUInt8 cmd[4];
225  cmd[0] = 0x02; // PAGE PROGRAM
226  cmd[1] = (addr>>16)&0xff;
227  cmd[2] = (addr>> 8)&0xff;
228  cmd[3] = (addr>> 0)&0xff;
229 
230  SPIInterface::Operation ops[2];
231  ops[0].ncycles = 4;
232  ops[0].in = cmd;
233  ops[0].out = NULL;
234 
235  ops[1].ncycles = N;
236  ops[1].in = cur;
237  ops[1].out = NULL;
238 
239  {
240  SPIDevice::Selector S(dev);
241  dev.interface()->cycles(2, ops);
242  }
243  }
244 
245  busyWait(timeout);
246 
247  // end of write phase
248  }
249 
250  // readback to verify by sector
251 
252  std::vector<epicsUInt8> scratch;
253 
254  const epicsUInt8 *cur = data;
255  bool ok = true;
256  for(epicsUInt32 addr=start; addr<end; addr+=info.sectorSize, cur+=info.sectorSize)
257  {
258  const epicsUInt32 N = std::min(info.sectorSize, end-addr);
259 
260  scratch.resize(N);
261 
262  read(addr, scratch);
263 
264  if(memcmp(cur, &scratch[0], N)!=0) {
265  printf("FLASH readback mis-match in sector 0x%06x\n", (unsigned)addr);
266  ok = false;
267  }
268  }
269 
270  if(!ok)
271  throw std::runtime_error("FLASH readback error");
272 }
epicsUInt32 pageSize
PAGE PROGRAM (0x02) size in bytes. Always a power of 2.
Definition: flash.h:38
double timeout() const
timeout in seconds for an individual cycle()
Definition: spi.cpp:41
virtual void cycles(size_t nops, const Operation *ops)
Definition: spi.cpp:25
epicsUInt32 capacity
total capacity in bytes
Definition: flash.h:38
epicsUInt32 sectorSize
SECTOR ERASE (0xd8) size in bytes. Always a power of 2.
Definition: flash.h:38
Definition: devObj.h:97
SPIInterface * interface() const
Definition: spi.h:59
void read(epicsUInt32 start, epicsUInt32 count, epicsUInt8 *in)
Definition: flash.cpp:124

◆ write() [2/2]

void mrf::CFIFlash::write ( epicsUInt32  start,
const std::vector< epicsUInt8 > &  out,
bool  strict = true 
)
inline

Definition at line 61 of file flash.h.

62  { write(start, out.size(), &out[0], strict); }
void write(epicsUInt32 start, epicsUInt32 count, const epicsUInt8 *out, bool strict=true)
Definition: flash.cpp:157

The documentation for this class was generated from the following files: