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