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 28

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

powered by: WebSVN 2.1.0

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