OpenCores
URL https://opencores.org/ocsvn/gecko3/gecko3/trunk

Subversion Repositories gecko3

[/] [gecko3/] [trunk/] [GECKO3COM/] [gecko3com-fw/] [firmware/] [src/] [spi_flash.c] - Blame information for rev 9

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 nussgipfel
/* GECKO3COM
2
 *
3
 * Copyright (C) 2008 by
4
 *   ___    ___   _   _
5
 *  (  _`\ (  __)( ) ( )
6
 *  | (_) )| (   | |_| |   Berne University of Applied Sciences
7
 *  |  _ <'|  _) |  _  |   School of Engineering and
8
 *  | (_) )| |   | | | |   Information Technology
9
 *  (____/'(_)   (_) (_)
10
 *
11
 *
12
 * This program is free software: you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation, either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 */
24
/************************************************************/
25
/** \file    spi_flash.c
26
 *************************************************************
27
 *  \author  Christoph Zimmermann
28
 *  \date    Date of creation: 17.09.2007
29
 *  \brief C code for the spi-flash Library
30
 *
31
 *  \details Library to access the SPI Flash devices from ST
32
 *         Microelectronics (now Numonyx) or Spansion.
33
 *         Supported densities:
34
 *         8, 16, 32 Mbit
35
 *
36
 *   \date 17.09.2007 first version, based on the m25p16.h header file
37
 *   \date 24. june 2009 code size optimization for the GECKO3COM firmware
38
 *
39
 */
40
#include "spi_flash.h"
41
#include "spi.h"
42
#include "debugprint.h"
43
#include "stdint.h"
44
 
45
SPI_flash xdata flash_dr;
46
 
47
 
48
 /** \brief Internal: Helper function to count the number of active (1) bits in a byte */
49
static unsigned char
50
count_bits8 (unsigned char v)
51
{
52
  unsigned char count = 0;
53
  if (v & (1 << 0)) count++;
54
  if (v & (1 << 1)) count++;
55
  if (v & (1 << 2)) count++;
56
  if (v & (1 << 3)) count++;
57
  if (v & (1 << 4)) count++;
58
  if (v & (1 << 5)) count++;
59
  if (v & (1 << 6)) count++;
60
  if (v & (1 << 7)) count++;
61
  return count;
62
}
63
 
64
 
65
static void
66
setup_enables (unsigned char enables)
67
{
68
  // Software enables are active high.
69
  // Hardware enables are active low.
70
 
71
  if(count_bits8(enables) > 1) {
72
    //print_info("en\n");
73
    return;
74
  }
75
  else {
76
    bitSPI_CLK = 0; //make shure spi_clk is low before we activate a device
77
    SPI_OE |= bmSPI_MASK;  //activate spi bus
78
    enables &= bmSPI_CS_MASK;
79
    SPI_CS_PORT |= bmSPI_CS_MASK;   //disable all chipselect signals
80
    SPI_CS_PORT &= ~enables;
81
    SPI_CS_OE |= enables;
82
  }
83
}
84
 
85
 
86
/** disables all SPI devices and sets the SPI and SPI CS signals to tri-state */
87
#define disable_all()   {setup_enables (0); SPI_OE &= ~bmSPI_MASK;}  
88
 
89
 
90
/** \brief Internal: Writes one byte to the SPI bus
91
 *
92
 * \param[in] data to write to the bus
93
 */
94
static void
95
write_byte_msb (unsigned char v);
96
 
97
 
98
/** \brief Internal: Writes a block of data to the SPI bus
99
 *
100
 * \param[in] pointer to a buffer to read the data from
101
 * \param[in] length of the data to read
102
 */
103
static void
104
write_bytes_msb (const xdata unsigned char *buf, unsigned char len);
105
 
106
 
107
/** \brief Internal: Reads a block of data from the SPI bus
108
 *
109
 * \param[in] pointer to a buffer to write the data to
110
 * \param[in] length of the data to read
111
 */
112
static void
113
read_bytes_msb (xdata unsigned char *buf, unsigned char len);
114
 
115
 
116
/** \brief Internal: Writes a block of data in reversed order to the SPI bus
117
 *
118
 * \param[in] pointer to a buffer to read the data from
119
 * \param[in] length of the data to read
120
 */
121
static void
122
write_bytes_msb_reversed (const xdata unsigned char *buf, unsigned char len);
123
 
124
 
125
/** \brief Checks if the SPI flash is busy */
126
int8_t spiflash_is_busy(xdata SPI_flash *flashPtr) {
127
  xdata uint8_t buffer[2];
128
 
129
  if(flashPtr->isBusy) {
130
    //ask flash if still busy;
131
    setup_enables(bmSPI_CS_FLASH);
132
 
133
    write_byte_msb(RDSR);
134
    read_bytes_msb(buffer, 2);
135
 
136
    disable_all();
137
 
138
    if((buffer[1] & 1) == 1) {
139
      return 1;
140
    }
141
    else {
142
      flashPtr->isBusy = 0;
143
    }
144
  }
145
 
146
  return 0;
147
}
148
 
149
 
150
/** \brief Initalizes the values in the SPI_flash struct after reading
151
 *  the device ID */
152
int8_t init_spiflash(xdata SPI_flash *flashPtr) {
153
 
154
  uint8_t xdata flashID[3];
155
  uint8_t *idPtr = flashID;
156
  int8_t  xdata memsize;
157
  uint32_t xdata maxAdress;
158
  uint32_t xdata capacity;
159
  uint16_t xdata pages;
160
  uint8_t  xdata sectors;
161
 
162
 
163
  /* init SPI */
164
  disable_all ();               /* disable all devs       */
165
  bitSPI_MOSI = 0;               /* idle state has CLK = 0 */
166
 
167
  ptrCheck(flashPtr);
168
 
169
  setup_enables(bmSPI_CS_FLASH);
170
  write_byte_msb(RDID);
171
  read_bytes_msb (flashID, 3);
172
  disable_all();
173
 
174
  if(*idPtr == MANUFACTURER_STM || *idPtr == MANUFACTURER_SPA) {
175
    idPtr++;
176
    if(*idPtr == MEMTYPE_STM) {
177
      memsize = 0;
178
    }
179
    else if(*idPtr == MEMTYPE_SPA) {
180
      memsize = 1;
181
    }
182
    else {
183
      return UNSUPPORTED_TYPE;
184
    }
185
 
186
    idPtr++;
187
    memsize += *idPtr;
188
 
189
 
190
    switch(memsize) {
191
      case MEMCAPACITY_32MBIT_STM :
192
        maxAdress = MAXADRESS_32MBIT;
193
        capacity = FLASH_SIZE_32MBIT;
194
        pages = FLASH_PAGE_COUNT_32MBIT;
195
        sectors = FLASH_SECTOR_COUNT_32MBIT;
196
        break;
197
      case MEMCAPACITY_16MBIT_STM :
198
        maxAdress = MAXADRESS_16MBIT;
199
        capacity = FLASH_SIZE_16MBIT;
200
        pages = FLASH_PAGE_COUNT_16MBIT;
201
        sectors = FLASH_SECTOR_COUNT_16MBIT;
202
        break;
203
      case MEMCAPACITY_8MBIT_STM :
204
        maxAdress = MAXADRESS_8MBIT;
205
        capacity = FLASH_SIZE_8MBIT;
206
        pages = FLASH_PAGE_COUNT_8MBIT;
207
        sectors = FLASH_SECTOR_COUNT_8MBIT;
208
        break;
209
      default :
210
        return UNSUPPORTED_TYPE;
211
    }
212
 
213
    flashPtr->maxAdress = maxAdress;
214
    flashPtr->capacity = capacity;
215
    flashPtr->pages = pages;
216
    flashPtr->sectors = sectors;
217
 
218
    return GOOD;
219
  }
220
  else {
221
    return UNSUPPORTED_TYPE;
222
  }
223
}
224
 
225
 
226
/** \brief Reads data from the SPI flash */
227
int8_t spiflash_read(xdata SPI_flash *flashPtr, xdata uint32_t *adress, xdata uint8_t *buffer, const uint16_t length) {
228
 
229
  //adrCheck(flashPtr, adress, length);
230
 
231
  while(spiflash_is_busy(flashPtr));
232
 
233
  //print_info("r\n");
234
 
235
  /* we do a bit dirty programming here:
236
   * the adress of the device is only 24bit long, so we misuse the upper 8bits to send the
237
   * read command to the spi flash. this avoids more complicated constructs. */
238
  *adress &= 0x00FFFFFF;
239
  *adress |= 0x03000000; //set the upper 8bit to the READ command
240
 
241
  /*printf_tiny("ad: %x,",((uint8_t*)adress)[2]);
242
  printf_tiny("%x,",((uint8_t*)adress)[1]);
243
  printf_tiny("%x\n",((uint8_t*)adress)[0]);
244
  */
245
 
246
  setup_enables(bmSPI_CS_FLASH);
247
 
248
  write_bytes_msb_reversed((uint8_t*)adress, 4);
249
  if (length != 0) {
250
    read_bytes_msb (buffer, length);
251
  }
252
 
253
  disable_all();
254
 
255
  return 1;
256
}
257
 
258
/** \brief deletes one sector (64 kbyte) of the SPI flash */
259
int8_t spiflash_erase(xdata SPI_flash *flashPtr, xdata uint32_t *adress) {
260
  while(spiflash_is_busy(flashPtr));
261
 
262
  setup_enables(bmSPI_CS_FLASH);
263
  write_byte_msb(WREN);
264
  disable_all();
265
 
266
  /* we do a bit dirty programming here:
267
   * the adress of the device is only 24bit long, so we misuse the upper 8bits to send the
268
   * read command to the spi flash. this avoids more complicated constructs. */
269
  *adress &= 0x00FFFFFF;
270
  *adress |= 0xD8000000; //set the upper 8bit to the SE (sector erase) command
271
 
272
  //print_info("e\n");  
273
 
274
  setup_enables(bmSPI_CS_FLASH);
275
  write_bytes_msb_reversed((uint8_t*)adress, 4);
276
  disable_all();
277
 
278
  flashPtr->isBusy = 1;
279
 
280
  return 1;
281
}
282
 
283
 
284
/** \brief deletes the whole SPI flash */
285
int8_t spiflash_erase_bulk(xdata SPI_flash *flashPtr) {
286
  while(spiflash_is_busy(flashPtr));
287
  setup_enables(bmSPI_CS_FLASH);
288
  write_byte_msb(WREN);
289
  disable_all();
290
 
291
  setup_enables(bmSPI_CS_FLASH);
292
  write_byte_msb(BE);
293
  disable_all();
294
 
295
  flashPtr->isBusy = 1;
296
 
297
  return 1;
298
}
299
 
300
 
301
/** \brief Writes data to the SPI flash */
302
int8_t spiflash_write(xdata SPI_flash *flashPtr, xdata uint32_t *adress, \
303
                      xdata uint8_t *buffer, uint16_t length) {
304
 
305
  xdata uint16_t writeableBytes;
306
 
307
  while(length > 0) {
308
 
309
    while(spiflash_is_busy(flashPtr));
310
 
311
    setup_enables(bmSPI_CS_FLASH);
312
    write_byte_msb(WREN);
313
    disable_all();
314
 
315
    writeableBytes = (uint16_t)(pageEnd(*adress)-*adress);
316
    writeableBytes ++;
317
 
318
    if(length > writeableBytes) {
319
      length -= writeableBytes;
320
    }
321
    else {
322
      writeableBytes = length;
323
      length = 0;
324
    }
325
 
326
    //print_info("w\n");
327
    //printf_tiny("%d\n",writeableBytes);    
328
 
329
    /* we do a bit dirty programming here:
330
     * the adress of the device is only 24bit long, so we misuse the upper 8bits to send the
331
     * read command to the spi flash. this avoids more complicated constructs. */
332
    *adress &= 0x00FFFFFF;
333
    *adress |= 0x02000000; //set the upper 8bit to the PP (page programm) command
334
 
335
    /*printf_tiny("ad: %x,",((uint8_t*)adress)[3]);
336
    printf_tiny("%x,",((uint8_t*)adress)[2]);
337
    printf_tiny("%x,",((uint8_t*)adress)[1]);
338
    printf_tiny("%x\n",((uint8_t*)adress)[0]);
339
    */
340
    setup_enables(bmSPI_CS_FLASH);
341
    write_bytes_msb_reversed((uint8_t*)adress, 4);  //send the adress
342
 
343
    /* the write_bytes_msb function can loop maximum 255 times, but a page is 256 long... */
344
    write_byte_msb(buffer[0]);
345
    buffer++;
346
    write_bytes_msb(buffer, writeableBytes-1);  //...thats why we split this to two writes
347
    disable_all();
348
 
349
    *adress += writeableBytes;
350
    buffer += writeableBytes;
351
    buffer--;      //adjust it because we incremented it once during the write
352
 
353
    flashPtr->isBusy = 1;
354
  }
355
 
356
  return 1;
357
}
358
 
359
/* ----------------------------------------------------------------
360
 * Internal functions
361
 */
362
static void
363
write_byte_msb (unsigned char v)
364
{
365
  //printf_tiny("0x%x",v);
366
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
367
  bitSPI_MOSI = v & 0x1;
368
  bitSPI_CLK = 1;
369
  bitSPI_CLK = 0;
370
 
371
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
372
  bitSPI_MOSI = v & 0x1;
373
  bitSPI_CLK = 1;
374
  bitSPI_CLK = 0;
375
 
376
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
377
  bitSPI_MOSI = v & 0x1;
378
  bitSPI_CLK = 1;
379
  bitSPI_CLK = 0;
380
 
381
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
382
  bitSPI_MOSI = v & 0x1;
383
  bitSPI_CLK = 1;
384
  bitSPI_CLK = 0;
385
 
386
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
387
  bitSPI_MOSI = v & 0x1;
388
  bitSPI_CLK = 1;
389
  bitSPI_CLK = 0;
390
 
391
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
392
  bitSPI_MOSI = v & 0x1;
393
  bitSPI_CLK = 1;
394
  bitSPI_CLK = 0;
395
 
396
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
397
  bitSPI_MOSI = v & 0x1;
398
  bitSPI_CLK = 1;
399
  bitSPI_CLK = 0;
400
 
401
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
402
  bitSPI_MOSI = v & 0x1;
403
  bitSPI_CLK = 1;
404
  bitSPI_CLK = 0;
405
}
406
 
407
static void
408
write_bytes_msb (const xdata unsigned char *buf, unsigned char len)
409
{
410
  while (len-- != 0){
411
    //printf_tiny("0x%x, ",*buf);
412
    write_byte_msb (*buf++);
413
  }
414
}
415
 
416
static void
417
write_bytes_msb_reversed (const xdata unsigned char *buf, unsigned char len)
418
{
419
  while (len-- != 0){
420
    //printf_tiny("0x%x, ",buf[len]);
421
    write_byte_msb (buf[len]);
422
  }
423
}
424
 
425
/** \brief Internal: Reads one byte from the SPI bus
426
 *
427
 * \return data read from the bus
428
 */
429
#if 0
430
/*
431
 * This is incorrectly compiled by SDCC 2.4.0
432
 */
433
/*static unsigned char
434
read_byte_msb (void)
435
{
436
  unsigned char v = 0;
437
 
438
  bitSPI_CLK = 1;
439
  v |= bitSPI_MISO;
440
  bitSPI_CLK = 0;
441
 
442
  v = v << 1;
443
  bitSPI_CLK = 1;
444
  v |= bitSPI_MISO;
445
  bitSPI_CLK = 0;
446
 
447
  v = v << 1;
448
  bitSPI_CLK = 1;
449
  v |= bitSPI_MISO;
450
  bitSPI_CLK = 0;
451
 
452
  v = v << 1;
453
  bitSPI_CLK = 1;
454
  v |= bitSPI_MISO;
455
  bitSPI_CLK = 0;
456
 
457
  v = v << 1;
458
  bitSPI_CLK = 1;
459
  v |= bitSPI_MISO;
460
  bitSPI_CLK = 0;
461
 
462
  v = v << 1;
463
  bitSPI_CLK = 1;
464
  v |= bitSPI_MISO;
465
  bitSPI_CLK = 0;
466
 
467
  v = v << 1;
468
  bitSPI_CLK = 1;
469
  v |= bitSPI_MISO;
470
  bitSPI_CLK = 0;
471
 
472
  v = v << 1;
473
  bitSPI_CLK = 1;
474
  v |= bitSPI_MISO;
475
  bitSPI_CLK = 0;
476
 
477
  return v;
478
  } */
479
#else
480
static unsigned char
481
read_byte_msb (void) _naked
482
{
483
  _asm
484
        clr     a
485
 
486
        setb    _bitSPI_CLK
487
        mov     c, _bitSPI_MISO
488
        rlc     a
489
        clr     _bitSPI_CLK
490
 
491
        setb    _bitSPI_CLK
492
        mov     c, _bitSPI_MISO
493
        rlc     a
494
        clr     _bitSPI_CLK
495
 
496
        setb    _bitSPI_CLK
497
        mov     c, _bitSPI_MISO
498
        rlc     a
499
        clr     _bitSPI_CLK
500
 
501
        setb    _bitSPI_CLK
502
        mov     c, _bitSPI_MISO
503
        rlc     a
504
        clr     _bitSPI_CLK
505
 
506
        setb    _bitSPI_CLK
507
        mov     c, _bitSPI_MISO
508
        rlc     a
509
        clr     _bitSPI_CLK
510
 
511
        setb    _bitSPI_CLK
512
        mov     c, _bitSPI_MISO
513
        rlc     a
514
        clr     _bitSPI_CLK
515
 
516
        setb    _bitSPI_CLK
517
        mov     c, _bitSPI_MISO
518
        rlc     a
519
        clr     _bitSPI_CLK
520
 
521
        setb    _bitSPI_CLK
522
        mov     c, _bitSPI_MISO
523
        rlc     a
524
        clr     _bitSPI_CLK
525
 
526
        mov     dpl,a
527
        ret
528
  _endasm;
529
}
530
#endif
531
 
532
static void
533
read_bytes_msb (xdata unsigned char *buf, unsigned char len)
534
{
535
  while (len-- != 0){
536
    *buf++ = read_byte_msb ();
537
  }
538
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.