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 36

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

powered by: WebSVN 2.1.0

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