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