Inclue macros for BV.
[bertos.git] / bertos / drv / flash25.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 serial Flash memory.
34  *
35  * Module provide a kfile interface, that ensure an abstraction
36  * from comunication channel and give a standard interface.
37  * Typicaly this kind of memory use an SPI bus, but you should
38  * use another comunication channel you have defined.
39  *
40  * \version $Id$
41  * \author Daniele Basile <asterix@develer.com>
42  */
43
44 /*
45  * We use a spi bus, thus include hardware specific definition.
46  * If you use another channel you must redefine this macros.
47  */
48 #include "hw_spi.h"
49
50 #include <appconfig.h>
51
52 #include <cfg/macros.h>
53 #include <cfg/debug.h>
54
55 #include <drv/timer.h>
56 #include <drv/flash25.h>
57
58 #if CONFIG_KERNEL
59 #include <kern/proc.h>
60 #endif
61
62
63 /**
64  * Global definition of channel handler (usually SPI).
65  */
66 static KFile *channel;
67
68 /**
69  * Wait until flash memory is ready.
70  */
71 static void flash25_waitReady(void)
72 {
73         uint8_t stat;
74
75         while (1)
76         {
77                 CS_ENABLE();
78
79                 kfile_putc(FLASH25_RDSR, channel);
80                 stat = kfile_getc(channel);
81
82                 CS_DISABLE();
83
84                 if (!(stat & RDY_BIT))
85                         break;
86                 #if CONFIG_KERNEL
87                 else
88                         proc_switch();
89                 #endif
90         }
91 }
92
93 /**
94  * Send a single command to serial flash memory.
95  */
96 static void flash25_sendCmd(Flash25Opcode cmd)
97 {
98         CS_ENABLE();
99
100         kfile_putc(cmd, channel);
101
102         CS_DISABLE();
103 }
104
105 /**
106  * flash25 init function.
107  * This function init a comunication channel and
108  * try to read manufacturer id of serial memory,
109  * then check if is equal to selected type.
110  */
111 static bool flash25_pin_init(void)
112 {
113         uint8_t device_id;
114         uint8_t manufacturer;
115
116         SPI_HW_INIT();
117
118         CS_ENABLE();
119         /*
120          * Send read id productor opcode on
121          * comunication channel
122          * TODO:controllare se ha senso
123          */
124         kfile_putc(FLASH25_RDID, channel);
125
126         manufacturer = kfile_getc(channel);
127         device_id = kfile_getc(channel);
128
129         CS_DISABLE();
130
131         if((FLASH25_MANUFACTURER_ID == manufacturer) &&
132                 (FLASH25_DEVICE_ID == device_id))
133                 return true;
134         else
135                 return false;
136 }
137
138 /**
139  * Reopen a serial memory interface.
140  *
141  * For serial memory this function reinit only
142  * the size and seek_pos in kfile stucture.
143  * Return a kfile pointer, after assert check.
144  */
145 static KFile * flash25_reopen(struct KFile *fd)
146 {
147         KFILE_ASSERT_GENERIC(fd);
148
149         fd->seek_pos = 0;
150         fd->size = FLASH25_MEM_SIZE;
151
152         kprintf("flash25 file opened\n");
153         return fd;
154 }
155
156 /**
157  * Close a serial memory interface.
158  *
159  * For serial memory this funtion do nothing,
160  * and return always 0.
161  */
162 static int flash25_close(UNUSED_ARG(struct KFile *,fd))
163 {
164         kprintf("flash25 file closed\n");
165         return 0;
166 }
167
168 /**
169  * Read \a _buf lenght \a size byte from serial flash memmory.
170  *
171  * For read in serial flash memory we
172  * enble cs pin and send one byte of read opcode,
173  * and then 3 byte of address of memory cell we
174  * want to read. After the last byte of address we
175  * can read data from so pin.
176  *
177  * \return the number of bytes read.
178  */
179 static size_t flash25_read(struct KFile *fd, void *buf, size_t size)
180 {
181         uint8_t *data = (uint8_t *)buf;
182
183         KFILE_ASSERT_GENERIC(fd);
184
185         ASSERT(fd->seek_pos + size <= fd->size);
186         size = MIN((uint32_t)size, fd->size - fd->seek_pos);
187
188         //kprintf("Reading at addr[%lu], size[%d]\n", fd->seek_pos, size);
189         CS_ENABLE();
190
191         kfile_putc(FLASH25_READ, channel);
192
193
194         /*
195          * Address that we want to read.
196          */
197         kfile_putc((fd->seek_pos >> 16) & 0xFF, channel);
198         kfile_putc((fd->seek_pos >> 8) & 0xFF, channel);
199         kfile_putc(fd->seek_pos & 0xFF, channel);
200
201         kfile_read(channel, data, size);
202
203         CS_DISABLE();
204
205         fd->seek_pos += size;
206
207         return size;
208 }
209
210 /**
211  * Write \a _buf in serial flash memory
212  *
213  * Before to write data into flash we must enable
214  * memory writing. To do this we send a WRE command opcode.
215  * After this command the flash is ready to be write, and so
216  * we send a PROGRAM opcode followed to 3 byte of
217  * address memory, at the end of last address byte
218  * we can send the data.
219  * When we finish to send all data, we disable cs
220  * and flash write received data bytes on its memory.
221  *
222  * \note: WARNING: you could write only on erased memory section!
223  * Each write time you could write max a memory page size,
224  * because if you write more than memory page size the
225  * address roll over to first byte of page.
226  *
227  * \return the number of bytes write.
228  */
229 static size_t flash25_write(struct KFile *fd, const void *_buf, size_t size)
230 {
231         flash25Offset_t offset;
232         flash25Size_t total_write = 0;
233         flash25Size_t wr_len;
234         const uint8_t *data = (const uint8_t *) _buf;
235
236         KFILE_ASSERT_GENERIC(fd);
237         ASSERT(fd->seek_pos + size <= fd->size);
238
239         size = MIN((flash25Size_t)size, fd->size - fd->seek_pos);
240
241         while (size)
242         {
243                 offset = fd->seek_pos % (flash25Size_t)FLASH25_PAGE_SIZE;
244                 wr_len = MIN((flash25Size_t)size, FLASH25_PAGE_SIZE - (flash25Size_t)offset);
245
246                 kprintf("[seek_pos-<%lu>, offset-<%d>]\n", fd->seek_pos, offset);
247
248                 /*
249                  * We check serial flash memory state, and wait until ready-flag
250                  * is high.
251                  */
252                 flash25_waitReady();
253
254                 /*
255                  * Start write cycle.
256                  * We could write only data not more long than one
257                  * page size.
258                  *
259                  * To write on serial flash memory we must first
260                  * enable write with a WREN opcode command, before
261                  * the PROGRAM opcode.
262                  *
263                  * \note: the same byte cannot be reprogrammed without
264                  * erasing the whole sector first.
265                  */
266                 flash25_sendCmd(FLASH25_WREN);
267
268                 CS_ENABLE();
269                 kfile_putc(FLASH25_PROGRAM, channel);
270
271                 /*
272                  * Address that we want to write.
273                  */
274                 kfile_putc((fd->seek_pos >> 16) & 0xFF, channel);
275                 kfile_putc((fd->seek_pos >> 8) & 0xFF, channel);
276                 kfile_putc(fd->seek_pos & 0xFF, channel);
277
278                 kfile_write(channel, data, wr_len);
279
280                 CS_DISABLE();
281
282                 data += wr_len;
283                 fd->seek_pos += wr_len;
284                 size -= wr_len;
285                 total_write += wr_len;
286         }
287
288         kprintf("written %u bytes\n", total_write);
289         return total_write;
290 }
291
292 /**
293  * Sector erase function.
294  *
295  * Erase a select \p sector of serial flash memory.
296  *
297  * \note A sector size is FLASH25_SECTOR_SIZE.
298  * This operation could take a while.
299  */
300 void flash25_sectorErase(Flash25Sector sector)
301 {
302
303         /*
304          * Erase a sector could take a while,
305          * for debug we measure that time
306          * see datasheet to compare this time.
307          */
308         DB(ticks_t start_time = timer_clock());
309
310         CS_ENABLE();
311
312         /*
313          * To erase a sector of serial flash memory we must first
314          * enable write with a WREN opcode command, before
315          * the SECTOR_ERASE opcode. Sector is automatically
316          * determinate if any address within the sector
317          * is selected.
318          */
319         kfile_putc(FLASH25_WREN, channel);
320         kfile_putc(FLASH25_SECTORE_ERASE, channel);
321
322         /*
323          * Address inside the sector that we want to
324          * erase.
325          */
326         kfile_putc(sector, channel);
327
328         CS_DISABLE();
329
330         /*
331          * We check serial flash memory state, and wait until ready-flag
332          * is hight.
333          */
334         flash25_waitReady();
335
336         DB(kprintf("Erased sector [%d] in %d ms\n", sector, ticks_to_ms(timer_clock() - start_time)));
337
338 }
339
340 /**
341  * Chip erase function.
342  *
343  * Erase all sector of serial flash memory.
344  *
345  * \note This operation could take a while.
346  */
347 void flash25_chipErase(void)
348 {
349         /*
350          * Erase all chip could take a while,
351          * for debug we measure that time
352          * see datasheet to compare this time.
353          */
354         DB(ticks_t start_time = timer_clock());
355
356         /*
357          * To erase serial flash memory we must first
358          * enable write with a WREN opcode command, before
359          * the CHIP_ERASE opcode.
360          */
361         flash25_sendCmd(FLASH25_WREN);
362         flash25_sendCmd(FLASH25_CHIP_ERASE);
363
364         /*
365          * We check serial flash memory state, and wait until ready-flag
366          * is high.
367          */
368         flash25_waitReady();
369
370         DB(kprintf("Erased all memory in %d ms\n", ticks_to_ms(timer_clock() - start_time)));
371
372 }
373
374 /**
375  * Init data flash memory interface.
376  */
377 void flash25_init(struct KFile *fd, struct KFile *_channel)
378 {
379          //Set kfile struct type as a generic kfile structure.
380         DB(fd->_type = KFT_GENERIC);
381
382         // Set up data flash programming functions.
383         fd->reopen = flash25_reopen;
384         fd->close = flash25_close;
385         fd->read = flash25_read;
386         fd->write = flash25_write;
387         fd->seek = kfile_genericSeek;
388
389         /*
390          * Init a local channel structure and flash kfile interface.
391          */
392         channel = _channel;
393         flash25_reopen(fd);
394
395         /*
396          * Init data flash memory and micro pin.
397          */
398         if (!flash25_pin_init())
399                 ASSERT(0);
400 }
401
402 #if CONFIG_TEST
403
404 /**
405  * Test function for flash25.
406  *
407  * \note: This implentation use a SPI channel.
408  */
409 bool flash25_test(KFile *channel)
410 {
411         KFile fd;
412         uint8_t test_buf[256];
413
414         /*
415          * Init a spi kfile interface and
416          * flash driver.
417          */
418         flash25_init(&fd, channel);
419
420         kprintf("Init serial flash\n");
421
422         flash25_chipErase();
423
424         flash25_sectorErase(FLASH25_SECT1);
425         flash25_sectorErase(FLASH25_SECT2);
426         flash25_sectorErase(FLASH25_SECT3);
427         flash25_sectorErase(FLASH25_SECT4);
428
429         /*
430          * Launche a kfile test interface.
431          */
432         kprintf("Kfile test start..\n");
433         if (!kfile_test(&fd, test_buf, NULL, sizeof(test_buf)))
434                 return false;
435
436         return true;
437 }
438 #endif /* CONFIG_TEST */