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 35

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 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 35 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 13 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
}
94 9 nussgipfel
 
95
/** \brief Internal: Writes one byte to the SPI bus
96
 *
97
 * \param[in] data to write to the bus
98
 */
99
static void
100
write_byte_msb (unsigned char v);
101
 
102
 
103
/** \brief Internal: Writes a block of data to the SPI bus
104
 *
105
 * \param[in] pointer to a buffer to read the data from
106
 * \param[in] length of the data to read
107
 */
108
static void
109
write_bytes_msb (const xdata unsigned char *buf, unsigned char len);
110
 
111
 
112
/** \brief Internal: Reads a block of data from the SPI bus
113
 *
114
 * \param[in] pointer to a buffer to write the data to
115
 * \param[in] length of the data to read
116
 */
117
static void
118
read_bytes_msb (xdata unsigned char *buf, unsigned char len);
119
 
120
 
121
/** \brief Internal: Writes a block of data in reversed order to the SPI bus
122
 *
123
 * \param[in] pointer to a buffer to read the data from
124
 * \param[in] length of the data to read
125
 */
126
static void
127
write_bytes_msb_reversed (const xdata unsigned char *buf, unsigned char len);
128
 
129
 
130
/** \brief Checks if the SPI flash is busy */
131
int8_t spiflash_is_busy(xdata SPI_flash *flashPtr) {
132
  xdata uint8_t buffer[2];
133
 
134
  if(flashPtr->isBusy) {
135
    //ask flash if still busy;
136
    setup_enables(bmSPI_CS_FLASH);
137
 
138
    write_byte_msb(RDSR);
139
    read_bytes_msb(buffer, 2);
140
 
141
    disable_all();
142
 
143
    if((buffer[1] & 1) == 1) {
144
      return 1;
145
    }
146
    else {
147
      flashPtr->isBusy = 0;
148
    }
149
  }
150
 
151
  return 0;
152
}
153
 
154
 
155
/** \brief Initalizes the values in the SPI_flash struct after reading
156
 *  the device ID */
157
int8_t init_spiflash(xdata SPI_flash *flashPtr) {
158
 
159
  uint8_t xdata flashID[3];
160
  uint8_t *idPtr = flashID;
161
  int8_t  xdata memsize;
162
  uint32_t xdata maxAdress;
163
  uint32_t xdata capacity;
164
  uint16_t xdata pages;
165
  uint8_t  xdata sectors;
166
 
167
 
168
  /* init SPI */
169
  disable_all ();               /* disable all devs       */
170
  bitSPI_MOSI = 0;               /* idle state has CLK = 0 */
171
 
172
  ptrCheck(flashPtr);
173 13 nussgipfel
 
174 9 nussgipfel
  setup_enables(bmSPI_CS_FLASH);
175
  write_byte_msb(RDID);
176
  read_bytes_msb (flashID, 3);
177
  disable_all();
178
 
179
  if(*idPtr == MANUFACTURER_STM || *idPtr == MANUFACTURER_SPA) {
180
    idPtr++;
181
    if(*idPtr == MEMTYPE_STM) {
182
      memsize = 0;
183
    }
184
    else if(*idPtr == MEMTYPE_SPA) {
185
      memsize = 1;
186
    }
187
    else {
188
      return UNSUPPORTED_TYPE;
189
    }
190
 
191
    idPtr++;
192
    memsize += *idPtr;
193
 
194
 
195
    switch(memsize) {
196
      case MEMCAPACITY_32MBIT_STM :
197
        maxAdress = MAXADRESS_32MBIT;
198
        capacity = FLASH_SIZE_32MBIT;
199
        pages = FLASH_PAGE_COUNT_32MBIT;
200
        sectors = FLASH_SECTOR_COUNT_32MBIT;
201
        break;
202
      case MEMCAPACITY_16MBIT_STM :
203
        maxAdress = MAXADRESS_16MBIT;
204
        capacity = FLASH_SIZE_16MBIT;
205
        pages = FLASH_PAGE_COUNT_16MBIT;
206
        sectors = FLASH_SECTOR_COUNT_16MBIT;
207
        break;
208
      case MEMCAPACITY_8MBIT_STM :
209
        maxAdress = MAXADRESS_8MBIT;
210
        capacity = FLASH_SIZE_8MBIT;
211
        pages = FLASH_PAGE_COUNT_8MBIT;
212
        sectors = FLASH_SECTOR_COUNT_8MBIT;
213
        break;
214
      default :
215
        return UNSUPPORTED_TYPE;
216
    }
217
 
218
    flashPtr->maxAdress = maxAdress;
219
    flashPtr->capacity = capacity;
220
    flashPtr->pages = pages;
221
    flashPtr->sectors = sectors;
222
 
223
    return GOOD;
224
  }
225
  else {
226
    return UNSUPPORTED_TYPE;
227 13 nussgipfel
    /* debug stuff: */
228
    //return *idPtr;
229 9 nussgipfel
  }
230
}
231
 
232
 
233
/** \brief Reads data from the SPI flash */
234
int8_t spiflash_read(xdata SPI_flash *flashPtr, xdata uint32_t *adress, xdata uint8_t *buffer, const uint16_t length) {
235
 
236
  //adrCheck(flashPtr, adress, length);
237
 
238
  while(spiflash_is_busy(flashPtr));
239
 
240
  //print_info("r\n");
241
 
242
  /* we do a bit dirty programming here:
243 13 nussgipfel
   * the adress of the device is only 24bit long, so we misuse the upper 8bits
244
   * to send the read command to the spi flash.
245
   * this avoids more complicated constructs. */
246 9 nussgipfel
  *adress &= 0x00FFFFFF;
247
  *adress |= 0x03000000; //set the upper 8bit to the READ command
248
 
249
  /*printf_tiny("ad: %x,",((uint8_t*)adress)[2]);
250
  printf_tiny("%x,",((uint8_t*)adress)[1]);
251
  printf_tiny("%x\n",((uint8_t*)adress)[0]);
252
  */
253
 
254
  setup_enables(bmSPI_CS_FLASH);
255
 
256
  write_bytes_msb_reversed((uint8_t*)adress, 4);
257
  if (length != 0) {
258
    read_bytes_msb (buffer, length);
259
  }
260
 
261
  disable_all();
262
 
263
  return 1;
264
}
265
 
266
/** \brief deletes one sector (64 kbyte) of the SPI flash */
267
int8_t spiflash_erase(xdata SPI_flash *flashPtr, xdata uint32_t *adress) {
268
  while(spiflash_is_busy(flashPtr));
269
 
270
  setup_enables(bmSPI_CS_FLASH);
271
  write_byte_msb(WREN);
272
  disable_all();
273
 
274
  /* we do a bit dirty programming here:
275 13 nussgipfel
   * the adress of the device is only 24bit long, so we misuse the upper 8bits
276
   * to send the read command to the spi flash.
277
   * this avoids more complicated constructs. */
278 9 nussgipfel
  *adress &= 0x00FFFFFF;
279
  *adress |= 0xD8000000; //set the upper 8bit to the SE (sector erase) command
280
 
281
  //print_info("e\n");  
282
 
283
  setup_enables(bmSPI_CS_FLASH);
284
  write_bytes_msb_reversed((uint8_t*)adress, 4);
285
  disable_all();
286
 
287
  flashPtr->isBusy = 1;
288
 
289
  return 1;
290
}
291
 
292
 
293
/** \brief deletes the whole SPI flash */
294
int8_t spiflash_erase_bulk(xdata SPI_flash *flashPtr) {
295
  while(spiflash_is_busy(flashPtr));
296
  setup_enables(bmSPI_CS_FLASH);
297
  write_byte_msb(WREN);
298
  disable_all();
299
 
300
  setup_enables(bmSPI_CS_FLASH);
301
  write_byte_msb(BE);
302
  disable_all();
303
 
304
  flashPtr->isBusy = 1;
305
 
306
  return 1;
307
}
308
 
309
 
310
/** \brief Writes data to the SPI flash */
311
int8_t spiflash_write(xdata SPI_flash *flashPtr, xdata uint32_t *adress, \
312
                      xdata uint8_t *buffer, uint16_t length) {
313
 
314
  xdata uint16_t writeableBytes;
315
 
316
  while(length > 0) {
317
 
318
    while(spiflash_is_busy(flashPtr));
319
 
320
    setup_enables(bmSPI_CS_FLASH);
321
    write_byte_msb(WREN);
322
    disable_all();
323
 
324
    writeableBytes = (uint16_t)(pageEnd(*adress)-*adress);
325
    writeableBytes ++;
326
 
327
    if(length > writeableBytes) {
328
      length -= writeableBytes;
329
    }
330
    else {
331
      writeableBytes = length;
332
      length = 0;
333
    }
334
 
335
    //print_info("w\n");
336
    //printf_tiny("%d\n",writeableBytes);    
337
 
338
    /* we do a bit dirty programming here:
339 13 nussgipfel
     * the adress of the device is only 24bit long, so we misuse the upper 8bits
340
     * to send the read command to the spi flash.
341
     * this avoids more complicated constructs. */
342 9 nussgipfel
    *adress &= 0x00FFFFFF;
343
    *adress |= 0x02000000; //set the upper 8bit to the PP (page programm) command
344
 
345
    /*printf_tiny("ad: %x,",((uint8_t*)adress)[3]);
346
    printf_tiny("%x,",((uint8_t*)adress)[2]);
347
    printf_tiny("%x,",((uint8_t*)adress)[1]);
348
    printf_tiny("%x\n",((uint8_t*)adress)[0]);
349
    */
350
    setup_enables(bmSPI_CS_FLASH);
351
    write_bytes_msb_reversed((uint8_t*)adress, 4);  //send the adress
352
 
353
    /* the write_bytes_msb function can loop maximum 255 times, but a page is 256 long... */
354
    write_byte_msb(buffer[0]);
355
    buffer++;
356
    write_bytes_msb(buffer, writeableBytes-1);  //...thats why we split this to two writes
357
    disable_all();
358
 
359
    *adress += writeableBytes;
360
    buffer += writeableBytes;
361
    buffer--;      //adjust it because we incremented it once during the write
362
 
363
    flashPtr->isBusy = 1;
364
  }
365
 
366
  return 1;
367
}
368
 
369
/* ----------------------------------------------------------------
370
 * Internal functions
371
 */
372
static void
373
write_byte_msb (unsigned char v)
374
{
375
  //printf_tiny("0x%x",v);
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
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
407
  bitSPI_MOSI = v & 0x1;
408
  bitSPI_CLK = 1;
409
  bitSPI_CLK = 0;
410
 
411
  v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
412
  bitSPI_MOSI = v & 0x1;
413
  bitSPI_CLK = 1;
414
  bitSPI_CLK = 0;
415
}
416
 
417
static void
418
write_bytes_msb (const xdata unsigned char *buf, unsigned char len)
419
{
420
  while (len-- != 0){
421
    //printf_tiny("0x%x, ",*buf);
422
    write_byte_msb (*buf++);
423
  }
424
}
425
 
426
static void
427
write_bytes_msb_reversed (const xdata unsigned char *buf, unsigned char len)
428
{
429
  while (len-- != 0){
430
    //printf_tiny("0x%x, ",buf[len]);
431
    write_byte_msb (buf[len]);
432
  }
433
}
434
 
435
/** \brief Internal: Reads one byte from the SPI bus
436
 *
437
 * \return data read from the bus
438
 */
439
#if 0
440
/*
441
 * This is incorrectly compiled by SDCC 2.4.0
442
 */
443
/*static unsigned char
444
read_byte_msb (void)
445
{
446
  unsigned char v = 0;
447
 
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
  v = v << 1;
478
  bitSPI_CLK = 1;
479
  v |= bitSPI_MISO;
480
  bitSPI_CLK = 0;
481
 
482
  v = v << 1;
483
  bitSPI_CLK = 1;
484
  v |= bitSPI_MISO;
485
  bitSPI_CLK = 0;
486
 
487
  return v;
488
  } */
489
#else
490
static unsigned char
491
read_byte_msb (void) _naked
492
{
493
  _asm
494
        clr     a
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
        setb    _bitSPI_CLK
527
        mov     c, _bitSPI_MISO
528
        rlc     a
529
        clr     _bitSPI_CLK
530
 
531
        setb    _bitSPI_CLK
532
        mov     c, _bitSPI_MISO
533
        rlc     a
534
        clr     _bitSPI_CLK
535
 
536
        mov     dpl,a
537
        ret
538
  _endasm;
539
}
540
#endif
541
 
542
static void
543
read_bytes_msb (xdata unsigned char *buf, unsigned char len)
544
{
545
  while (len-- != 0){
546
    *buf++ = read_byte_msb ();
547
  }
548
}

powered by: WebSVN 2.1.0

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