Implement write, read, seek function. Change dflash prefix into dataflash.
[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 dataflash_t previous_page = 0;
59 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         /*
95          * Send opcode.
96          */
97         spi_sendRecv(opcode);
98
99         /*
100          *  Send page address.
101          * \{
102          */
103         spi_sendRecv((uint8_t)(page_addr >> (16 - DATAFLASH_PAGE_ADDRESS_BIT)));
104         spi_sendRecv((uint8_t)((page_addr << (DATAFLASH_PAGE_ADDRESS_BIT - 8)) + (byte_addr >> 8)));
105         /*\}*/
106
107         /*
108          * Send byte page address.
109          */
110         spi_sendRecv((uint8_t)byte_addr);
111
112         /* \} */
113
114 }
115
116 /**
117  * Reset dataflash memory function.
118  *
119  * This function reset data flash memory
120  * with one pulse reset long about 10usec.
121  *
122  */
123 static void dataflash_reset(void)
124 {
125         CS_ENABLE();
126         RESET_ENABLE();
127         timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
128         CS_DISABLE();
129         RESET_DISABLE();
130         timer_delayHp(us_to_hptime(RESET_PULSE_WIDTH));
131 }
132
133 /**
134  * dataflash init function.
135  * This function initialize a micro pin and
136  * SPI driver, and test if data flash memory
137  * density is the same wich define in dataflash.h.
138  */
139 MOD_DEFINE(dataflash);
140 static bool dataflash_pin_init(void)
141 {
142         uint8_t stat;
143
144         MOD_CHECK(spi);
145
146         RESET_DISABLE();
147         WRITE_ENABLE(); //pilot wp pin.
148
149         RESET_OUT();
150         WP_OUT();
151
152         dataflash_reset();
153
154         stat = dataflash_stat();
155
156         MOD_INIT(dataflash);
157
158         /*
159          * 2,3,4,5 bits of 1 byte status register
160          * indicate a device density of dataflash memory
161          * (see datasheet for more detail.)
162          */
163         GET_ID_DESITY_DEVICE(stat);
164
165         if(stat == DATAFLASH_ID_DEVICE_DENSITY)
166                 return true;
167         else
168                 return false;
169
170 }
171
172
173 /**
174  * Read status register of dataflah memory.
175  *
176  */
177 static uint8_t dataflash_stat(void)
178 {
179         uint8_t stat;
180
181         /*
182          * Make sure to toggle CS signal in order,
183          * and reset dataflash command decoder.
184          * \{
185          */
186         CS_TOGGLE();
187
188         stat = spi_sendRecv(DFO_READ_STATUS);
189         stat = spi_sendRecv(0x00);
190
191         return stat;
192 }
193
194
195 /**
196  * Send one command to data flash memory, and
197  * return status register value.
198  *
199  */
200 static uint8_t dataflash_cmd(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode)
201 {
202
203         send_cmd(page_addr, byte_addr, opcode);
204
205         CS_DISABLE();
206         CS_ENABLE();
207
208         /*
209          * We chech data flash memory state, and wait until busy-flag
210          * is hight.
211          */
212         while(!(dataflash_stat() & BUSY_BIT));
213
214         return (dataflash_stat());
215
216 }
217
218 /**
219  * Read one byte from main data flash memory or buffer data
220  * flash memory.
221  */
222 static uint8_t dataflash_read_byte(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode)
223 {
224         uint8_t data;
225
226         send_cmd(page_addr, byte_addr, opcode);
227
228 #if CONFIG_DATA_FLASH == DATAFLASH_AT45DB041B
229         if(opcode == DFO_READ_FLASH_MEM_BYTE)
230         {
231                 /*
232                  * Send 24 don't care bit.
233                  * \{
234                  */
235                 spi_sendRecv(0x00);
236                 spi_sendRecv(0x00);
237                 spi_sendRecv(0x00);
238                 /* \} */
239
240         }
241 #endif
242
243         spi_sendRecv(0x00);         //Send 8 don't care bit.
244         data = spi_sendRecv(0x00);  //Read byte.
245         CS_DISABLE();
246
247         return data;
248 }
249
250 /**
251  * Read \a len bytes from main data flash memory or buffer data
252  * flash memory, and put it in \a *block.
253  */
254 static void dataflash_read_block(dataflash_t page_addr, dataflash_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len)
255 {
256
257         send_cmd(page_addr, byte_addr, opcode);
258
259         if(opcode == DFO_READ_FLASH_MEM_BYTE)
260         {
261                 /*
262                  * Send 24 don't care bit.
263                  * \{
264                  */
265                 spi_sendRecv(0x00);
266                 spi_sendRecv(0x00);
267                 spi_sendRecv(0x00);
268                 /* \} */
269         }
270
271         spi_sendRecv(0x00);   //Send 8 don't care bit.
272         spi_read(block, len); //Read len bytes ad put in block buffer.
273
274
275         CS_DISABLE();
276
277 }
278
279
280 /**
281  * Write \a len bytes in buffer buffer data flash memory.
282  *
283  * \note Isn't possible to write bytes directly in main memory data
284  * flash. To perform write in main memory you must before write in buffer
285  * data flash memory, an then send command to write page in main memory.
286  */
287 static void dataflash_write_block(dataflash_t byte_addr, DataFlashOpcode opcode, uint8_t *block, dataflashSize_t len)
288 {
289
290         send_cmd(0x00, byte_addr, opcode);
291
292         spi_write(block, len); //Write len bytes.
293
294         CS_DISABLE();
295
296 }
297
298
299 /**
300  * Load selct page from dataflash memory to buffer.
301  */
302 static void dataflash_loadPage(dataflash_t page_addr)
303 {
304         dataflash_cmd(page_addr, 0x00, DFO_MOV_MEM_TO_BUFF1);
305
306         CS_DISABLE();
307 }
308
309 /**
310  * Flush select page (stored in buffer) in data flash main memory page.
311  */
312 void dataflash_flush(void)
313 {
314         if (page_modified)
315         {
316                 dataflash_cmd(previous_page, 0x00, DFO_WRITE_BUFF1_TO_MEM_E);
317
318                 CS_DISABLE();
319                 page_modified = false;
320
321                 kprintf("\n::=> Flush page:... <%ld>\n", previous_page);
322         }
323 }
324
325 /* Kfile interface section */
326
327 /**
328  * Open data flash file \a fd
329  * \a name and \a mode are unused, cause flash memory is
330  * threated like one file.
331  */
332 static bool dataflash_open(struct _KFile *fd, UNUSED_ARG(const char *, name), UNUSED_ARG(int, mode))
333 {
334         MOD_CHECK(dataflash);
335
336         previous_page = 0;
337         fd->seek_pos = 0;
338         fd->size = (dataflashAddr_t)DATAFLASH_PAGE_SIZE *       (dataflashAddr_t)DATAFLASH_NUM_PAGE;
339
340         /* Load select page memory from data flash memory*/
341         dataflash_loadPage(previous_page);
342
343         kprintf("dataflash file opened\n");
344         return true;
345 }
346
347 /**
348  * Close file \a fd
349  */
350 static bool dataflash_close(UNUSED_ARG(struct _KFile *,fd))
351 {
352         dataflash_flush();
353         kprintf("dataflash file closed\n");
354         return true;
355 }
356
357 /**
358  * Move \a fd file seek position of \a offset bytes
359  * from current position.
360  */
361 static int32_t dataflash_seek(struct _KFile *fd, int32_t offset, KSeekMode whence)
362 {
363         uint32_t seek_pos;
364
365         switch(whence)
366         {
367                 case KSM_SEEK_SET:
368                         seek_pos = 0;
369                         break;
370                 case KSM_SEEK_END:
371                         seek_pos = fd->size - 1;
372                         break;
373                 case KSM_SEEK_CUR:
374                         seek_pos = fd->seek_pos;
375                         break;
376                 default:
377                         ASSERT(0);
378                         return -1;
379                         break;
380         }
381
382         /* Bound check */
383         if (seek_pos + offset > fd->size)
384         {
385                 ASSERT(0);
386                 return -1;
387         }
388
389         fd->seek_pos = seek_pos + offset;
390         kprintf("Flash seek to [%u]\n", fd->seek_pos);
391
392         return fd->seek_pos;
393 }
394
395 /**
396  * Read from file \a fd \a size bytes and put it in buffer \a buf
397  * \return the number of bytes read.
398  */
399 static size_t dataflash_read(struct _KFile *fd, void *buf, size_t size)
400 {
401         dataflashAddr_t byte_addr;
402         dataflashAddr_t page_addr;
403         uin8_t *data = (uint8_t *)buf;
404
405
406         ASSERT(fd->seek_pos + size <= fd->size);
407         size = MIN((uint32_t)size, fd->size - fd->seek_pos);
408
409         kprintf("Reading at pos[%u]\n", fd->seek_pos);
410
411         /*
412          * We select from absolute address page address
413          * and byte address in page.
414          * \{
415          */
416         page_addr = fd->seek_pos / (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
417         byte_addr = fd->seek_pos % (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
418         /* \} */
419
420         kprintf(" [page-<%ld>, byte-<%ld>]", page_addr, byte_addr);
421
422         /*
423          * Flush current page in main memory if
424          * we had been written a byte in memory
425          */
426         dataflash_flush();
427
428         /*
429          * Read byte in main page data flash memory.
430          */
431         dataflash_read_block(page_addr, byte_addr, DFO_READ_FLASH_MEM_BYTE, data, size);
432
433         fd->seek_pos += size;
434         kprintf(" ::=> Read data: %02x\n",data);
435
436         return size;
437 }
438
439 /**
440  * Write program memory.
441  * Write \a size bytes from buffer \a _buf to file \a fd
442  * \note Write operations are buffered.
443  */
444 static size_t dataflash_write(struct _KFile *fd, const void *_buf, size_t size)
445 {
446
447         dataflashAddr_t byte_addr;
448         dataflashAddr_t current_page;
449
450         uint8_t *data = (uint8_t *) _buf;
451
452         ASSERT(fd->seek_pos + size <= fd->size);
453         size = MIN((uint32_t)size, fd->size - fd->seek_pos);
454
455         kprintf("Writing at pos[%u]\n", fd->seek_pos);
456
457         while (size)
458         {
459                 /*
460                 * We select from absolute address page address
461                 * and byte address in page.
462                 * \{
463                 */
464                 current_page = fd->seek_pos / (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
465                 byte_addr = fd->seek_pos % (dataflashAddr_t)DATAFLASH_PAGE_SIZE;
466                 /* \} */
467
468                 size_t wr_len = MIN(size, DATAFLASH_PAGE_SIZE - byte_addr);
469
470                 kprintf(" [page-<%ld>, byte-<%ld>]",current_page, byte_addr);
471
472                 if (current_page != previous_page)
473                 {
474                         /* Flush current page in main memory*/
475                         dataflash_flush();
476                         /* Load select page memory from data flash memory*/
477                         dataflash_loadPage(current_page);
478
479                         previous_page = current_page;
480                         kprintf(" >> Load page: <%ld> ",current_page);
481                 }
482                 /*
483                 * Write byte in current page, and set true
484                 * page_modified flag.
485                 *\{
486                 */
487                 dataflash_write_byte(byte_addr, DFO_WRITE_BUFF1, data);
488                 page_modified = true;
489                 /* \} */
490
491                 data += wr_len;
492                 fd->seek_pos += wr_len;
493                 size -= wr_len;
494                 total_write += wr_len;
495         }
496
497         kprintf("written %u bytes\n", total_write);
498         return total_write;
499 }
500
501 /**
502  * Init data flash memory interface.
503  */
504 void dataflash_init(struct _KFile *fd)
505 {
506         // Set up data flash programming functions.
507         fd->open = dataflash_open;
508         fd->close = dataflash_close;
509         fd->read = dataflash_read;
510         fd->write = dataflash_write;
511         fd->seek = dataflash_seek;
512
513         // Init data flash memory and micro pin.
514         ASSERT(dataflash_pin_init());
515 }