Make static the global variable. Remove doxygen brackect from some comment. Change...
[bertos.git] / drv / dataflash.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  *  \brief Function library for AT45DBXX Data Flash memory.
34  *
35  *
36  * \version $Id: dataflash.c 15379 2007-03-28 15:46:09Z asterix $
37  * \author Daniele Basile <asterix@develer.com>
38  */
39
40
41 #include <appconfig.h>
42
43 #include <avr/io.h>
44 #include <cfg/macros.h>
45 #include <cfg/debug.h>
46 #include <cfg/module.h>
47 #include <drv/timer.h>
48 #include <drv/spi.h>
49 #include <drv/dataflash.h>
50
51 #include "hw_spi.h"
52
53
54 /**
55  * Global variable for store current and previous data
56  * flash memory page address during operation of writing.
57  */
58 static dataflash_t previous_page = 0;
59 static bool page_modified = false;
60
61
62 /**
63  * Send a generic command to data flash memory.
64  * This function send only 4 byte, for opcode, page address and
65  * byte address.
66  */
67 static void send_cmd(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode)
68 {
69
70         /*
71          * Make sure to toggle CS signal in order,
72          * and reset dataflash command decoder.
73          *
74          * \note This is equivalent to CS_DISABLE() immediately followed by CS_ENABLE()
75          */
76         CS_TOGGLE();
77
78
79         /*
80          * To send one command to data flash memory, we send 4 byte.
81          * First byte is opcode command, second and third byte are
82          * page address, in last byte we write a byte page address.
83          * (see datasheet for more detail).
84          *
85          * \note Generaly a defaul memory page size is more than 256 byte.
86          *  In this case we need for addressing a byte in one page more than
87          *  8 bit, so we put in fourth byte low part of address byte, and
88          *  hight part of address byte in third byte togheter low par of page
89          *  address.
90          *
91          */
92
93         /*
94          * Send opcode.
95          */
96         spi_sendRecv(opcode);
97
98         /*
99          *  Send page address.
100          */
101         spi_sendRecv((uint8_t)(page_addr >> (16 - DATAFLASH_PAGE_ADDRESS_BIT)));
102         spi_sendRecv((uint8_t)((page_addr << (DATAFLASH_PAGE_ADDRESS_BIT - 8)) + (byte_addr >> 8)));
103
104         /*
105          * Send byte page address.
106          */
107         spi_sendRecv((uint8_t)byte_addr);
108
109
110 }
111
112 /**
113  * Reset dataflash memory function.
114  *
115  * This function reset data flash memory
116  * with one pulse reset long about 10usec.
117  *
118  */
119 static void dataflash_reset(void)
120 {
121         CS_ENABLE();
122         RESET_ENABLE();
123         timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
124         CS_DISABLE();
125         RESET_DISABLE();
126         timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
127 }
128
129 /**
130  * dataflash init function.
131  * This function initialize a micro pin and
132  * SPI driver, and test if data flash memory
133  * density is the same wich define in dataflash.h.
134  */
135 MOD_DEFINE(dataflash);
136 static bool dataflash_pin_init(void)
137 {
138         uint8_t stat;
139
140         MOD_CHECK(spi);
141
142         RESET_DISABLE();
143         WRITE_ENABLE(); //pilot wp pin.
144
145         RESET_OUT();
146         WP_OUT();
147
148         dataflash_reset();
149
150         stat = dataflash_stat();
151
152         MOD_INIT(dataflash);
153
154         /*
155          * 2,3,4,5 bits of 1 byte status register
156          * indicate a device density of dataflash memory
157          * (see datasheet for more detail.)
158          */
159         GET_ID_DESITY_DEVICE(stat);
160
161         if(stat == DATAFLASH_ID_DEVICE_DENSITY)
162                 return true;
163         else
164                 return false;
165
166 }
167
168
169 /**
170  * Read status register of dataflah memory.
171  *
172  */
173 static uint8_t dataflash_stat(void)
174 {
175         uint8_t stat;
176
177         /*
178          * Make sure to toggle CS signal in order,
179          * and reset dataflash command decoder.
180          */
181         CS_TOGGLE();
182
183         stat = spi_sendRecv(DFO_READ_STATUS);
184         stat = spi_sendRecv(0x00);
185
186         return stat;
187 }
188
189
190 /**
191  * Send one command to data flash memory, and
192  * return status register value.
193  *
194  */
195 static uint8_t dataflash_cmd(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode)
196 {
197
198         send_cmd(page_addr, byte_addr, opcode);
199
200         CS_TOGGLE();
201
202         /*
203          * We chech data flash memory state, and wait until busy-flag
204          * is hight.
205          */
206         while(!(dataflash_stat() & BUSY_BIT));
207
208         return (dataflash_stat());
209
210 }
211
212 /**
213  * Read one byte from main data flash memory or buffer data
214  * flash memory.
215  */
216 static uint8_t dataflash_read_byte(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode)
217 {
218         uint8_t data;
219
220         send_cmd(page_addr, byte_addr, opcode);
221
222 #if CONFIG_DATA_FLASH == DATAFLASH_AT45DB041B
223         if(opcode == DFO_READ_FLASH_MEM_BYTE)
224         {
225                 /*
226                  * Send 24 don't care bit.
227                  */
228                 spi_sendRecv(0x00);
229                 spi_sendRecv(0x00);
230                 spi_sendRecv(0x00);
231
232         }
233 #endif
234
235         spi_sendRecv(0x00);         //Send 8 don't care bit.
236         data = spi_sendRecv(0x00);  //Read byte.
237         CS_DISABLE();
238
239         return data;
240 }
241
242 /**
243  * Read \a len bytes from main data flash memory or buffer data
244  * flash memory, and put it in \a *block.
245  */
246 static void dataflash_read_block(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len)
247 {
248
249         send_cmd(page_addr, byte_addr, opcode);
250
251         if(opcode == DFO_READ_FLASH_MEM_BYTE)
252         {
253                 /*
254                  * Send 24 don't care bit.
255                  */
256                 spi_sendRecv(0x00);
257                 spi_sendRecv(0x00);
258                 spi_sendRecv(0x00);
259
260         }
261
262         spi_sendRecv(0x00);   //Send 8 don't care bit.
263         spi_read(block, len); //Read len bytes ad put in block buffer.
264
265
266         CS_DISABLE();
267
268 }
269
270
271 /**
272  * Write \a len bytes in buffer buffer data flash memory.
273  *
274  * \note Isn't possible to write bytes directly in main memory data
275  * flash. To perform write in main memory you must before write in buffer
276  * data flash memory, an then send command to write page in main memory.
277  */
278 static void dataflash_write_block(dataflash_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len)
279 {
280
281         send_cmd(0x00, byte_addr, opcode);
282
283         spi_write(block, len); //Write len bytes.
284
285         CS_DISABLE();
286
287 }
288
289
290 /**
291  * Load selct page from dataflash memory to buffer.
292  */
293 static void dataflash_loadPage(dataflash_t page_addr)
294 {
295         dataflash_cmd(page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1);
296
297         CS_DISABLE();
298 }
299
300 /**
301  * Flush select page (stored in buffer) in data flash main memory page.
302  */
303 void dataflash_flush(void)
304 {
305         if (page_modified)
306         {
307                 dataflash_cmd(previous_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E);
308
309                 CS_DISABLE();
310                 page_modified = false;
311
312                 kprintf("\n::=> Flush page:... <%ld>\n", previous_page);
313         }
314 }
315
316 /* Kfile interface section */
317
318 /**
319  * Open data flash file \a fd
320  * \a name and \a mode are unused, cause flash memory is
321  * threated like one file.
322  */
323 static bool dataflash_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode))
324 {
325         MOD_CHECK(dataflash);
326
327         previous_page = 0;
328         fd->seek_pos = 0;
329         fd->size = (dataflashAddr_t)DATAFLASH_PAGE_SIZE *       (dataflashAddr_t)DATAFLASH_NUM_PAGE;
330
331         /* Load select page memory from data flash memory*/
332         dataflash_loadPage(previous_page);
333
334         kprintf("dataflash file opened\n");
335         return true;
336 }
337
338 /**
339  * Close file \a fd
340  */
341 static bool dataflash_close(UNUSED_ARG(struct _KFile *,fd))
342 {
343         dataflash_flush();
344         kprintf("dataflash file closed\n");
345         return true;
346 }
347
348 /**
349  * Move \a fd file seek position of \a offset bytes
350  * from current position.
351  */
352 static int32_t dataflash_seek(struct _KFile *fd, int32_t offset, KSeekMode whence)
353 {
354         uint32_t seek_pos;
355
356         switch(whence)
357         {
358                 case KSM_SEEK_SET:
359                         seek_pos = 0;
360                         break;
361                 case KSM_SEEK_END:
362                         seek_pos = fd->size - 1;
363                         break;
364                 case KSM_SEEK_CUR:
365                         seek_pos = fd->seek_pos;
366                         break;
367                 default:
368                         ASSERT(0);
369                         return -1;
370                         break;
371         }
372
373         /* Bound check */
374         if (seek_pos + offset > fd->size)
375         {
376                 ASSERT(0);
377                 return -1;
378         }
379
380         fd->seek_pos = seek_pos + offset;
381         kprintf("Flash seek to [%u]\n", fd->seek_pos);
382
383         return fd->seek_pos;
384 }
385
386 /**
387  * Read from file \a fd \a size bytes and put it in buffer \a buf
388  * \return the number of bytes read.
389  */
390 static size_t dataflash_read(struct _KFile *fd, void *buf, size_t size)
391 {
392         dataflashAddr_t byte_addr;
393         dataflashAddr_t page_addr;
394         uin8_t *data = (uint8_t *)buf;
395
396
397         ASSERT(fd->seek_pos + size <= fd->size);
398         size = MIN((uint32_t)size, fd->size - fd->seek_pos);
399
400         kprintf("Reading at pos[%u]\n", fd->seek_pos);
401
402         /*
403          * We select from absolute address page address
404          * and byte address in page.
405          */
406         page_addr = fd->seek_pos / (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
407         byte_addr = fd->seek_pos % (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
408
409
410         kprintf(" [page-<%ld>, byte-<%ld>]", page_addr, byte_addr);
411
412         /*
413          * Flush current page in main memory if
414          * we had been written a byte in memory
415          */
416         dataflash_flush();
417
418         /*
419          * Read byte in main page data flash memory.
420          */
421         dataflash_read_block(page_addr, byte_addr, DFO_READ_FLASH_MEM_BYTE, data, size);
422
423         fd->seek_pos += size;
424         kprintf(" ::=> Read data: %02x\n",data);
425
426         return size;
427 }
428
429 /**
430  * Write program memory.
431  * Write \a size bytes from buffer \a _buf to file \a fd
432  * \note Write operations are buffered.
433  */
434 static size_t dataflash_write(struct _KFile *fd, const void *_buf, size_t size)
435 {
436
437         dataflashAddr_t byte_addr;
438         dataflashAddr_t current_page;
439
440         uint8_t *data = (uint8_t *) _buf;
441
442         ASSERT(fd->seek_pos + size <= fd->size);
443         size = MIN((uint32_t)size, fd->size - fd->seek_pos);
444
445         kprintf("Writing at pos[%u]\n", fd->seek_pos);
446
447         while (size)
448         {
449                 /*
450                 * We select from absolute address page address
451                 * and byte address in page.
452                 */
453                 current_page = fd->seek_pos / (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
454                 byte_addr = fd->seek_pos % (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
455
456
457                 size_t wr_len = MIN(size, DATAFLASH_PAGE_SIZE - byte_addr);
458
459                 kprintf(" [page-<%ld>, byte-<%ld>]",current_page, byte_addr);
460
461                 if (current_page != previous_page)
462                 {
463                         /* Flush current page in main memory*/
464                         dataflash_flush();
465                         /* Load select page memory from data flash memory*/
466                         dataflash_loadPage(current_page);
467
468                         previous_page = current_page;
469                         kprintf(" >> Load page: <%ld> ",current_page);
470                 }
471                 /*
472                 * Write byte in current page, and set true
473                 * page_modified flag.
474                 */
475                 dataflash_write_byte(byte_addr, DFO_WRITE_BUFF1, data);
476                 page_modified = true;
477
478
479                 data += wr_len;
480                 fd->seek_pos += wr_len;
481                 size -= wr_len;
482                 total_write += wr_len;
483         }
484
485         kprintf("written %u bytes\n", total_write);
486         return total_write;
487 }
488
489 /**
490  * Init data flash memory interface.
491  */
492 void dataflash_init(struct _KFile *fd)
493 {
494         // Set up data flash programming functions.
495         fd->open = dataflash_open;
496         fd->close = dataflash_close;
497         fd->read = dataflash_read;
498         fd->write = dataflash_write;
499         fd->seek = dataflash_seek;
500
501         // Init data flash memory and micro pin.
502         ASSERT(dataflash_pin_init());
503 }
504
505 /**
506  * Test function for dataflash.
507  *
508  * This function test check low level driver for
509  * AT45xx (see dataflash.h for more info) data flash memory.
510  * We write a string in memory in some page ad read it.
511  */
512 void dataflash_test(void)
513 {
514         KFile fd;
515
516         dataflash_init(&fd);
517
518         uint8_t test_buf[] = "0123456789 Develer s.r.l.";
519         uint8_t cmp_buf[];
520
521         kprintf("\n======= Data Flash test function =========================================\n");
522         kprintf("\nThe string test is: %s\n\n", test_buf);
523
524         fd.open(&fd, NULL, 0);
525
526         /*  TEST 1 */
527
528         // Seek to addr 0
529         if (fd.seek(&fd, 0, SEEK_SET) != 0)
530                 goto dataflash_test_end;
531
532         // Test flash write to address 0 (page 0)
533         if (!fd->write(&fd, test_buf, sizeof(test_buf)))
534                 goto dataflash_test_end;
535
536         // Seek to addr 0
537         if (fd.seek(&fd, 0, SEEK_SET) != 0)
538                 goto dataflash_test_end;
539
540         // Test flash read to address 0 (page 0)
541         if (!fd->read(&fd, cmp_buf, sizeof(test_buf)))
542                 goto dataflash_test_end;
543
544         // Compare if are egual.
545         if ((memcmp(cmp_buf,test_buf, sizeof(test_buf)) == 0)
546                 goto dataflash_test_end;
547
548         /*  TEST 2 */
549
550         // Go to middle address memory.
551         fd.seek(&fd, (((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) / 2), SEEK_CUR);
552
553         // Test flash write at the middle of memory
554         if (!fd->write(&fd, test_buf, sizeof(test_buf)))
555                 goto dataflash_test_end;
556
557         // Go to middle address memory.
558         fd.seek(&fd, (((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) / 2), SEEK_CUR);
559
560         // Test flash read  at the middle of memory
561         if (!fd->read(&fd, cmp_buf, sizeof(test_buf)))
562                 goto dataflash_test_end;
563
564         // Compare if are egual.
565         if ((memcmp(cmp_buf,test_buf, sizeof(test_buf)) == 0)
566                 goto dataflash_test_end;
567
568         /*  TEST 3 */
569
570         // Go to end of data flash.
571         fd.seek(&fd, ((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) - sizeof(test_buf), SEEK_END);
572
573         // Test flash write at the end of memory
574         if (!fd->write(&fd, test_buf, sizeof(test_buf)))
575                 goto dataflash_test_end;
576
577         // Go to end of data flash.
578         fd.seek(&fd, ((dataflashAddr_t)DFLASH_PAGE_SIZE * (dataflashAddr_t)DFLASH_NUM_PAGE) - sizeof(test_buf), SEEK_END);
579
580         // Test flash read at the end of memory
581         if (!fd->read(&fd, cmp_buf, sizeof(test_buf)))
582                 goto dataflash_test_end;
583
584         // Compare if are egual.
585         if ((memcmp(cmp_buf,test_buf, sizeof(test_buf)) == 0)
586                 goto dataflash_test_end;
587
588         kprintf("\n");
589
590         kprintf("\n====== Test end ===========================================================\n");
591         fd.close(&fd);
592         return true;
593
594 dataflash_test_end:
595         fd.close(&fd);
596         return false;
597
598 }