libpropeller
Making PropellerGCC Easier
 All Classes Files Functions Variables Enumerations Enumerator Macros Pages
sdsafespi.h
Go to the documentation of this file.
1 
2 #ifndef LIBPROPELLER_SDSAFESPI_H_
3 #define LIBPROPELLER_SDSAFESPI_H_
4 
5 #include <propeller.h>
6 
7 #define YIELD() __asm__ volatile( "" ::: "memory" )
8 
9 
10 #define RET_IF_ERROR_INT if(HasError()){return error;}
11 #define RET_IF_ERROR if(HasError()){return;}
12 #define THROW_INT(value) {SetErrorCode((value)); return error;}
13 #define THROW(value) {SetErrorCode((value)); return;}
14 
41 class SDSafeSPI {
42 public:
43  static const int kCardTypeMMC = 1;
44  static const int kCardTypeSD = 2;
45  static const int kCardTypeSDHC = 3;
46 
47  static const int kNoError = 0;
48 
49  static const int kErrorCardNotReset = -1;
50  static const int kError3v3NotSupported = -2;
51  static const int kErrorOcrFailed = -3;
52  static const int kErrorBlockNotLongAligned = -4;
53  // These errors are for the assembly engine...they are negated inside, and need to be <= 511
54  static const int kErrorAsmNoReadToken = 100;
55  static const int kErrorAsmBlockNotWritten = 101;
56  // NOTE: errors -128 to -255 are reserved for reporting R1 response errors
57  static const int kErrorSpiEngineNotRunning = -999;
58  static const int kErrorCardBusyTimeout = -1000;
59 
70  int Start(const int basepin) {
71  return Start(basepin, (basepin + 1), (basepin + 2), (basepin + 3));
72  }
73 
82  int Start(const int pin_do, const int pin_clk,
83  const int pin_di, const int pin_cs) {
84 
85  // Do all of the card initialization in C++, then hand off the pin
86  // information to the assembly cog for hot SPI block R/W action!
87  error = kNoError;
88 
89  Stop();
90  waitcnt((CLKFREQ >> 6) + CNT); // ~ equal to CLKFREQ * 4 / 1000
91 
92  mask_do = 1 << pin_do;
93  mask_di = 1 << pin_di;
94  mask_cs = 1 << pin_cs;
95  mask_clk = 1 << pin_clk;
96  mask_all = mask_cs | (1 << pin_clk) | mask_di;
97 
98  volatile uint8_t * ldat = dat();
99  ((int *) & ldat[1172])[0] = pin_do; // pinDo
100  ((int *) & ldat[1184])[0] = mask_do; // maskDo
101  ((int *) & ldat[1176])[0] = pin_clk; //pinClk
102  ((int *) & ldat[1180])[0] = pin_di; //pinDI
103  ((int *) & ldat[1188])[0] = mask_di; //maskDI
104  ((int *) & ldat[1192])[0] = mask_cs; //maskCS
105  ((int *) & ldat[1200])[0] = 9; //adrShift //block = 512 * index, and 512 = 1 << 9
106 
107  ((int *) & ldat[1196])[0] = mask_all; // pass the output pin mask via the command register
108  DIRA |= mask_all;
109 
110  // get the card in a ready state: set DI and CS high, send => 74 clocks
111  OUTA |= mask_all;
112  for (int i = 0; i < 4096; i++) {
113  OUTA |= 1 << pin_clk;
114  OUTA &= ~(1 << pin_clk);
115  }
116 
117  spi_block_index = CNT; //Time hack
118 
119  int TmpA = 0;
120  for (int i = 0; i < 10; i++) {
121  if (TmpA != 1) {
122  TmpA = SendCommandSlow(Cmd0, 0, 0x95);
123  if (TmpA & 4) {
124  // the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode
125  if (i & 1) {
126  // exit multiblock read mode
127 
128  for (int jk = 0; jk < 4; jk++) {
129  ReadSlow32(); // these extra clocks are required for some MMC cards
131  }
132  SendSlow(0xFD, 8); // stop token
133  ReadSlow32();
135 
136  while (ReadSlow() != 0xFF) {
138  }
140  } else {
141  // exit multiblock read mode
142  SendCommandSlow(Cmd12, 0, 0x61);
143  }
144  }
145  }
146 
147  }
148  if (TmpA != 1) {
149  // the reset command failed!
151  }
152 
153  int card_type = 0;
154  if (SendCommandSlow(Cmd8, 426, 135) == 1) { // Is this a SD type 2 card?
155  // Type2 SD, check to see if it's a SDHC card
156 
157  if ((ReadSlow32() & 0x1ff) != 0x1AA) { //check the supported voltage
160 
161  }
163 
164  // try to initialize the type 2 card with the High Capacity bit
165  while (SendCommandSlow(Acmd41, ((1 << 30)), 0x77)) {
166  YIELD();
167  }
168 
169  // the card is initialized, let's read back the High Capacity bit
170  if (SendCommandSlow(Cmd58, 0, 0xFD) != 0) {
172  }
173 
174 
175  // get back the data
176  if (ReadSlow32() & (1 << 30)) { //Check the bit
177  card_type = kCardTypeSDHC;
178  ((int *) & ldat[1200])[0] = 0; // adrShift
179  } else {
180  card_type = kCardTypeSD;
181  }
182  RET_IF_ERROR_INT; // For the previous ReadSlow32
183  } else {
184  // Either a type 1 SD card, or it's MMC, try SD 1st
185  if (SendCommandSlow(Acmd41, 0, 0xE5) < 2) {
186  // this is a type 1 SD card (1 means busy, 0 means done initializing)
187  card_type = kCardTypeSD;
188  while (SendCommandSlow(Acmd41, 0, 0xE5)) {
189  YIELD();
190  }
191  } else {
192  // mark that it's MMC, and try to initialize
193  card_type = kCardTypeMMC;
194  while (SendCommandSlow(Cmd1, 0, 0xF9)) {
195  YIELD();
196  }
197  }
198 
199  // some SD or MMC cards may have the wrong block size, set it here
200  SendCommandSlow(Cmd16, 512, 0x15);
201  }
202 
203  // card is mounted, make sure the CRC is turned off
204  SendCommandSlow(Cmd59, 0, 0x91);
205 
206  // done with the SPI bus for now
207  OUTA |= mask_cs;
208 
209  // set my counter modes for super fast SPI operation
210 
211  // writing: NCO single-ended mode, output on DI
212  ((int *) & ldat[1212])[0] = (0b00100 << 26) | (pin_di << 0);
213 
214  ((int *) & ldat[1220])[0] = (0b00100 << 26) | (pin_clk << 0); // NCO, 50% duty cycle
215 
216  ((int *) & ldat[1216])[0] = CLKFREQ >> (1 + 2 + 3); // how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)?
217 
218  // how long should we wait before auto-exiting any multiblock mode?
219  const int idle_limit = 125; // ms, NEVER make this > 1000
220  ((int *) & ldat[1256])[0] = CLKFREQ / (1000 / idle_limit); // convert to counts
221 
222  // Hand off control to the assembly engine's cog
223  ((int *) & ldat[1204])[0] = (int) (&spi_buffer_address);
224  ((int *) & ldat[1208])[0] = (int) (&spi_block_index);
225  spi_command = 0;
226 
227  spi_engine_cog = (cognew((int) (&(*(int *) & ldat[0])), (int) (&spi_command)) + 1);
228 
229  if (spi_engine_cog == 0) {
231  }
232 
233  while (spi_command != (-1)) {
234  YIELD();
235  }
236 
237  DIRA &= ~mask_all;
238  return card_type;
239  }
240 
241  void ReadBlock(const int block_index, char * buffer_address) {
242  if (spi_engine_cog == 0) {
244 
245  }
246  if ((int) buffer_address & 0x3) {
248 
249  }
250  spi_block_index = block_index;
251  spi_buffer_address = buffer_address;
252  spi_command = 'r';
253  while (spi_command == 'r') {
254  YIELD();
255  }
256  if (spi_command < 0) {
257  THROW(spi_command);
258  }
259  }
260 
261  void WriteBlock(const int block_index, char * buffer_address) {
262  if (spi_engine_cog == 0) {
264 
265  }
266  if ((int) buffer_address & 0x3) {
268  }
269  spi_block_index = block_index;
270  spi_buffer_address = buffer_address;
271  spi_command = 'w';
272  while (spi_command == 'w') {
273  YIELD();
274  }
275 
276  if (spi_command < 0) {
277  THROW(spi_command);
278  }
279  }
280 
288  void ReleaseCard(void) {
289  // I do not want to abort if the cog is not
290  // running, as this is called from stop, which
291  // is called from start/ [8^)
292 
293  if (spi_engine_cog) {
294  spi_command = 'z';
295  while (spi_command == 'z') {
296  YIELD();
297  }
298  }
299 
300  }
301 
304  void Stop(void) {
305  ReleaseCard();
306  if (spi_engine_cog) {
307  cogstop(spi_engine_cog - 1);
308  spi_engine_cog = 0;
309  }
310  }
311 
317  bool HasError(void) const {
318  return error != kNoError;
319  }
320 
323  void ClearError(void) {
324  error = kNoError;
325  }
326 
329  int GetError(void) const {
330  return error;
331  }
332 
333 private:
334  //volatile static unsigned char dat[];
335 
336  int mask_all;
337  int mask_do;
338  int mask_di;
339  int mask_cs;
340  int mask_clk;
341 
342  int error;
343  int spi_engine_cog;
344 
345  // these are used for interfacing with the assembly engine
346  volatile int spi_command;
347  volatile int spi_block_index; // which 512-byte block to read/write
348  volatile char * spi_buffer_address; // Accessed by the GAS cog, and points to a data buffer.
349 
354  void SetErrorCode(const int abort_code) {
355  // and we no longer need to control any pins from here
356  DIRA &= ~mask_all;
357  error = abort_code;
358  //return Abort_code;
359  }
360 
375  int SendCommandSlow(int command, int value, int crc) {
376  // if this is an application specific command, handle it
377  if (command & 0x80) {
378  // ACMD<n> is the command sequence of CMD55-CMD<n>
379  command &= 0x7f;
380  int ReplyA = SendCommandSlow(Cmd55, 0, 0x65);
381  if (ReplyA > 1) {
382  return ReplyA;
383  }
384  }
385 
386  // the CS line needs to go low during this operation
387  OUTA |= mask_cs;
388  OUTA &= ~mask_cs;
389 
390  // give the card a few cocks to finish whatever it was doing
391  ReadSlow32();
393  SendSlow(command, 8);
394  SendSlow(value, 32);
395  SendSlow(crc, 8);
396  if (command == Cmd12) { // if so, stuff byte
397  ReadSlow();
399  }
400 
401  // read back the response (spec declares 1-8 reads max for SD, MMC is 0-8)
402  int ReplyB;
403  int Time_stamp = 9;
404  do {
405  ReplyB = ReadSlow();
407  } while ((ReplyB & 0x80) && (Time_stamp--));
408  return ReplyB;
409  }
410 
411  void SendSlow(int value, const int bits_to_send) {
412  value = __builtin_propeller_rev(value, 32 - bits_to_send);
413 
414  for (int i = 0; i < bits_to_send; i++) {
415  OUTA &= ~mask_clk;
416  if (value & 1) {
417  OUTA |= mask_di;
418  } else {
419  OUTA &= ~mask_di;
420  }
421  value = ((unsigned) value) >> 1;
422  OUTA |= mask_clk;
423  }
424  }
425 
431  int ReadSlow32(void) {
432  int R = 0;
433  for (int i = 0; i < 4; i++) {
434  R <<= 8;
435  R |= ReadSlow();
437  }
438  return R;
439  }
440 
447  int ReadSlow(void) {
448  OUTA |= mask_di; // we need the DI line high so a read can occur
449 
450  int result = 0;
451  for (int i = 0; i < 8; i++) { // Get 8 bits
452  OUTA &= ~mask_clk;
453  OUTA |= mask_clk;
454  result += result + ((INA & mask_do) ? 1 : 0);
455  }
456  if ((CNT - spi_block_index) > (CLKFREQ << 2)) {
459  }
460  return result;
461  }
462 
463 
464  // SRLM: I don't know what these functions do...
465 
466  int GetSeconds(void) {
467  if (spi_engine_cog == 0) {
469  }
470  spi_command = 't';
471  // seconds are in SPI_block_index, remainder is in SPI_buffer_address
472  while (spi_command == 't') {
473  YIELD();
474  }
475  return spi_block_index;
476  }
477 
478  int GetMilliseconds(void) {
479  if (spi_engine_cog == 0) {
481  }
482  spi_command = 't';
483  //seconds are in SPI_block_index, remainder is in SPI_buffer_address
484  while (spi_command == 't') {
485  YIELD();
486  }
487  int milliseconds = (spi_block_index * 1000);
488  milliseconds = (milliseconds + (((int) spi_buffer_address * 1000) / CLKFREQ));
489  return milliseconds;
490  }
491 
492  // SDHC/SD/MMC command set for SPI
493  static const int Cmd0 = 0x40 + 0;
494  static const int Cmd1 = 0x40 + 1;
495  static const int Acmd41 = 0xC0 + 41;
496  static const int Cmd8 = 0x40 + 8;
497  static const int Cmd9 = 0x40 + 9;
498  static const int Cmd10 = 0x40 + 10;
499  static const int Cmd12 = 0x40 + 12;
500  static const int Cmd13 = 0x40 + 13;
501  static const int Acmd13 = 0xC0 + 13;
502  static const int Cmd16 = 0x40 + 16;
503  static const int Cmd17 = 0x40 + 17;
504  static const int Cmd18 = 0x40 + 18;
505  static const int Cmd23 = 0x40 + 23;
506  static const int Acmd23 = 0xC0 + 23;
507  static const int Cmd24 = 0x40 + 24;
508  static const int Cmd25 = 0x40 + 25;
509  static const int Cmd55 = 0x40 + 55;
510  static const int Cmd58 = 0x40 + 58;
511  static const int Cmd59 = 0x40 + 59;
512 
513  static volatile uint8_t * dat() {
514  static volatile uint8_t data[] = {
515  0x2f, 0xf1, 0xbf, 0xa0, 0x31, 0xf3, 0xbf, 0xa0, 0x2b, 0xed, 0xbf, 0xa0, 0x01, 0x80, 0xfe, 0xa4,
516  0xf0, 0x81, 0x3e, 0x08, 0xf1, 0x8b, 0xbe, 0xa0, 0xa4, 0x66, 0xfd, 0x5c, 0xf0, 0x81, 0xbe, 0x08,
517  0x00, 0x80, 0x7e, 0xc3, 0x06, 0x00, 0x78, 0x5c, 0x72, 0x80, 0x7e, 0x86, 0x1d, 0x00, 0x68, 0x5c,
518  0x77, 0x80, 0x7e, 0x86, 0x2d, 0x00, 0x68, 0x5c, 0x7a, 0x80, 0x7e, 0x86, 0x16, 0x00, 0x68, 0x5c,
519  0x74, 0x80, 0x7e, 0x86, 0x2e, 0x6f, 0x2a, 0x08, 0x2d, 0x71, 0x2a, 0x08, 0x00, 0x80, 0xfe, 0xa0,
520  0xf0, 0x81, 0x3e, 0x08, 0x06, 0x00, 0x7c, 0x5c, 0x7a, 0x82, 0xfe, 0xa0, 0x01, 0x76, 0xfe, 0xa4,
521  0x01, 0x84, 0xfe, 0xa4, 0x35, 0x96, 0xfc, 0x5c, 0x41, 0x81, 0xbe, 0xa0, 0xf0, 0x81, 0x3e, 0x08,
522  0x06, 0x00, 0x7c, 0x5c, 0x2e, 0x85, 0xbe, 0x08, 0x42, 0x7f, 0xbe, 0xa0, 0x01, 0x7e, 0xfe, 0x80,
523  0x3b, 0x7f, 0x3e, 0x86, 0x72, 0x78, 0x6a, 0x86, 0x25, 0x00, 0x68, 0x5c, 0x72, 0x82, 0xfe, 0xa0,
524  0x35, 0x96, 0xfc, 0x5c, 0x10, 0x78, 0xfd, 0x58, 0xb4, 0x8a, 0xfd, 0x5c, 0x41, 0x81, 0xbe, 0xa0,
525  0xf0, 0x81, 0x3e, 0x08, 0x72, 0x82, 0xfe, 0xa0, 0x01, 0x84, 0xfe, 0x80, 0x35, 0x96, 0xfc, 0x5c,
526  0x06, 0x00, 0x7c, 0x5c, 0x2e, 0x85, 0xbe, 0x08, 0x11, 0x78, 0xfd, 0x58, 0xb4, 0x8a, 0xfd, 0x5c,
527  0x41, 0x81, 0xbe, 0xa0, 0xf0, 0x81, 0x3e, 0x08, 0x77, 0x82, 0xfe, 0xa0, 0x35, 0x96, 0xfc, 0x5c,
528  0x06, 0x00, 0x7c, 0x5c, 0x42, 0x77, 0x3e, 0x86, 0x3c, 0x83, 0x2a, 0x86, 0x42, 0x00, 0x68, 0x5c,
529  0x77, 0x78, 0x7e, 0x86, 0x5a, 0xc4, 0xe8, 0x5c, 0x72, 0x78, 0x7e, 0x86, 0x53, 0xac, 0xe8, 0x5c,
530  0x77, 0x82, 0x7e, 0x86, 0x57, 0xb2, 0xe8, 0x5c, 0x72, 0x82, 0x7e, 0x86, 0x50, 0xa4, 0xe8, 0x5c,
531  0x7a, 0x82, 0x7e, 0x86, 0x4c, 0x9e, 0xe8, 0x5c, 0x42, 0x77, 0xbe, 0xa0, 0x01, 0x76, 0xfe, 0x80,
532  0x41, 0x79, 0xbe, 0xa0, 0x77, 0x82, 0x7e, 0x86, 0xf0, 0x48, 0xea, 0x5c, 0x72, 0x82, 0x7e, 0x86,
533  0xc6, 0xde, 0xe9, 0x5c, 0x7a, 0x82, 0x7e, 0x86, 0x00, 0x82, 0xea, 0xa0, 0x00, 0x00, 0x7c, 0x5c,
534  0x2a, 0xe9, 0xbf, 0x68, 0x8d, 0x46, 0xfd, 0x5c, 0x8d, 0x46, 0xfd, 0x5c, 0x00, 0x00, 0x7c, 0x5c,
535  0xa4, 0x86, 0xfe, 0x58, 0x63, 0xf6, 0xfc, 0x5c, 0x00, 0x00, 0x7c, 0x5c, 0x98, 0x86, 0xfe, 0x58,
536  0x63, 0xf6, 0xfc, 0x5c, 0x7c, 0x00, 0xfd, 0x5c, 0x00, 0x00, 0x7c, 0x5c, 0xb2, 0x86, 0xfe, 0x58,
537  0x63, 0xf6, 0xfc, 0x5c, 0x00, 0x00, 0x7c, 0x5c, 0x7c, 0x00, 0xfd, 0x5c, 0x10, 0x7e, 0xfe, 0xa0,
538  0x8d, 0x46, 0xfd, 0x5c, 0x5c, 0x7e, 0xfe, 0xe4, 0xfa, 0xf9, 0xff, 0x58, 0x81, 0x18, 0xfd, 0x5c,
539  0x8d, 0x46, 0xfd, 0x5c, 0x7c, 0x00, 0xfd, 0x5c, 0x00, 0x00, 0x7c, 0x5c, 0x2b, 0xed, 0xbf, 0xa0,
540  0x2a, 0xe9, 0xbf, 0x68, 0x2a, 0xe9, 0xbf, 0x64, 0x8d, 0x46, 0xfd, 0x5c, 0x43, 0xf9, 0xbf, 0xa0,
541  0x81, 0x18, 0xfd, 0x5c, 0x42, 0xf9, 0xbf, 0xa0, 0x2c, 0xf9, 0xbf, 0x2c, 0x81, 0x18, 0xfd, 0x5c,
542  0x01, 0xf8, 0xff, 0x24, 0x81, 0x18, 0xfd, 0x5c, 0x01, 0xf8, 0xff, 0x24, 0x81, 0x18, 0xfd, 0x5c,
543  0x01, 0xf8, 0xff, 0x24, 0x81, 0x18, 0xfd, 0x5c, 0x8d, 0x46, 0xfd, 0x5c, 0x18, 0x86, 0xfe, 0x28,
544  0x4c, 0x86, 0x7e, 0x86, 0x8d, 0x46, 0xe9, 0x5c, 0x09, 0x7e, 0xfe, 0xa0, 0x8d, 0x46, 0xfd, 0x5c,
545  0x80, 0x7c, 0x7e, 0x63, 0x77, 0x7e, 0xf2, 0xe4, 0x3e, 0x83, 0x96, 0xa4, 0x00, 0x00, 0x7c, 0x5c,
546  0x30, 0x7f, 0xbe, 0xa0, 0x8d, 0x46, 0xfd, 0x5c, 0xff, 0x7c, 0x7e, 0x86, 0x7d, 0x7e, 0xd6, 0xe4,
547  0x00, 0x00, 0x7c, 0x5c, 0x29, 0xe9, 0xbf, 0x64, 0x00, 0xfa, 0xff, 0xa0, 0x80, 0xf6, 0xff, 0x58,
548  0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
549  0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x00, 0xf6, 0xff, 0xa0,
550  0x00, 0x00, 0x7c, 0x5c, 0x01, 0xf8, 0xff, 0xa4, 0x00, 0x7c, 0xfe, 0xa0, 0xc0, 0xfa, 0xff, 0x58,
551  0x40, 0xf6, 0xff, 0x58, 0xf2, 0x51, 0x3e, 0x61, 0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61,
552  0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61, 0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61,
553  0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61, 0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61,
554  0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61, 0x01, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61,
555  0x00, 0xf6, 0xff, 0xa0, 0x01, 0x7c, 0xfe, 0x34, 0x00, 0xf8, 0xff, 0xa0, 0x00, 0x00, 0x7c, 0x5c,
556  0xf1, 0x7f, 0xbe, 0xa0, 0x3f, 0x73, 0xbe, 0x80, 0x45, 0x73, 0xbe, 0x84, 0x3f, 0x71, 0xbe, 0x80,
557  0x45, 0x71, 0xbe, 0x84, 0x3f, 0x8b, 0xbe, 0xa0, 0x00, 0x7e, 0xfe, 0x08, 0x3f, 0x71, 0xbe, 0xe1,
558  0x00, 0x6e, 0xfe, 0xc8, 0x3a, 0x73, 0x3e, 0x87, 0xb3, 0x00, 0x70, 0x5c, 0x7a, 0x82, 0xfe, 0xa0,
559  0x01, 0x76, 0xfe, 0xa4, 0x01, 0x84, 0xfe, 0xa4, 0x35, 0x96, 0xfc, 0x5c, 0x00, 0x00, 0x7c, 0x5c,
560  0x32, 0xf3, 0xbf, 0xa0, 0x01, 0xf6, 0xff, 0xa0, 0x2d, 0x89, 0xbe, 0x08, 0x04, 0x7a, 0xfe, 0xa0,
561  0x46, 0x79, 0xfd, 0x54, 0x3f, 0x7f, 0xbe, 0x08, 0x20, 0x7e, 0xfe, 0xa0, 0x44, 0xfb, 0xbf, 0xa0,
562  0xfd, 0x01, 0xbc, 0x08, 0x35, 0x79, 0xbd, 0x80, 0xbc, 0x7e, 0xfe, 0xe4, 0x36, 0x79, 0xbd, 0x84,
563  0x04, 0x88, 0xfe, 0x80, 0xb9, 0x7a, 0xfe, 0xe4, 0x00, 0xf6, 0xff, 0xa0, 0x00, 0xfa, 0xff, 0xa0,
564  0x31, 0xf3, 0xbf, 0xa0, 0x00, 0x00, 0x7c, 0x5c, 0x46, 0xcd, 0xfd, 0x54, 0x80, 0x7a, 0xfe, 0xa0,
565  0x30, 0x7f, 0xbe, 0xa0, 0x8d, 0x46, 0xfd, 0x5c, 0xfe, 0x7c, 0x7e, 0x86, 0xc9, 0x7e, 0xd6, 0xe4,
566  0x64, 0x82, 0xd6, 0xa4, 0xef, 0x00, 0x54, 0x5c, 0x01, 0xf8, 0xff, 0xa4, 0x80, 0x7a, 0xfe, 0xa0,
567  0x04, 0x7e, 0xfe, 0xa0, 0xc0, 0xfa, 0xff, 0x58, 0x40, 0xf6, 0xff, 0x58, 0xf2, 0x51, 0x3e, 0x61,
568  0x08, 0x7c, 0xfe, 0x34, 0xf2, 0x51, 0x3e, 0x61, 0x02, 0x7c, 0xfe, 0x70, 0xf2, 0x51, 0x3e, 0x61,
569  0x04, 0x7c, 0xfe, 0x70, 0xf2, 0x51, 0x3e, 0x61, 0x08, 0x7c, 0xfe, 0x70, 0xf2, 0x51, 0x3e, 0x61,
570  0x10, 0x7c, 0xfe, 0x70, 0xf2, 0x51, 0x3e, 0x61, 0x20, 0x7c, 0xfe, 0x70, 0xf2, 0x51, 0x3e, 0x61,
571  0x40, 0x7c, 0xfe, 0x70, 0xf2, 0x51, 0x3e, 0x61, 0x00, 0xf6, 0xff, 0xa0, 0x80, 0x7c, 0xfe, 0x70,
572  0xd2, 0x7e, 0xfe, 0xe4, 0x00, 0x7c, 0xfe, 0x3c, 0x3e, 0x01, 0xbc, 0xa0, 0x33, 0xcd, 0xbd, 0x80,
573  0xd0, 0x7a, 0xfe, 0xe4, 0x00, 0xf8, 0xff, 0xa0, 0x8d, 0x46, 0xfd, 0x5c, 0x8d, 0x46, 0xfd, 0x5c,
574  0x8d, 0x46, 0xfd, 0x5c, 0x00, 0x72, 0xfe, 0xa0, 0x00, 0x82, 0xfe, 0xa0, 0x00, 0x00, 0x7c, 0x5c,
575  0x46, 0xed, 0xfd, 0x50, 0x80, 0x7a, 0xfe, 0xa0, 0x7c, 0x00, 0xfd, 0x5c, 0xf8, 0xf9, 0xff, 0x58,
576  0x81, 0x18, 0xfd, 0x5c, 0x00, 0xfa, 0xff, 0xa0, 0x46, 0xf9, 0xbf, 0xa0, 0x01, 0xec, 0xfd, 0x80,
577  0x18, 0xf8, 0xff, 0x24, 0x80, 0xf6, 0xff, 0x58, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
578  0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
579  0x01, 0xf8, 0xff, 0x24, 0x11, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
580  0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
581  0x01, 0xf8, 0xff, 0x24, 0x11, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
582  0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
583  0x01, 0xf8, 0xff, 0x24, 0x11, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
584  0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24, 0x01, 0xf8, 0xff, 0x24,
585  0x01, 0xf8, 0xff, 0x24, 0x00, 0xf6, 0xff, 0xa0, 0xf6, 0x7a, 0xfe, 0xe4, 0x8d, 0x46, 0xfd, 0x5c,
586  0x8d, 0x46, 0xfd, 0x5c, 0x8d, 0x46, 0xfd, 0x5c, 0x1f, 0x7c, 0xfe, 0x60, 0x05, 0x7c, 0x7e, 0x86,
587  0x00, 0x82, 0xea, 0xa0, 0x65, 0x82, 0xd6, 0xa4, 0x8d, 0x46, 0xfd, 0x5c, 0x00, 0x72, 0xfe, 0xa0,
588  0x00, 0x00, 0x7c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590  0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591  0x40, 0x42, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x02, 0x00, 0x00,
592  0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
594  0x00, 0x00, 0x00, 0x00,
595  };
596  return data;
597  }
598 
599 };
600 
601 #endif // LIBPROPELLER_SDSAFESPI_H_