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