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