flash25.c

Go to the documentation of this file.
00001 
00044 #include <avr/io.h>
00045 
00046 #include <cfg/macros.h>
00047 #include <cfg/debug.h>
00048 
00049 #include <drv/timer.h>
00050 #include <drv/flash25.h>
00051 
00052 #if CONFIG_KERNEL
00053 #include <kern/proc.h>
00054 #endif
00055 
00056 /*
00057  * We use a spi bus, thus include hardware specific definition.
00058  * If you use another channel you must redefine this macros.
00059  */
00060 #include "hw_spi.h"
00061 
00062 #include <appconfig.h>
00063 
00067 static KFile *channel;
00068 
00072 static void flash25_waitReady(void)
00073 {
00074     uint8_t stat;
00075 
00076     while (1)
00077     {
00078         CS_ENABLE();
00079 
00080         kfile_putc(FLASH25_RDSR, channel);
00081         stat = kfile_getc(channel);
00082 
00083         CS_DISABLE();
00084 
00085         if (!(stat & RDY_BIT))
00086             break;
00087         #if CONFIG_KERNEL
00088         else
00089             proc_switch();
00090         #endif
00091     }
00092 }
00093 
00097 static void flash25_sendCmd(Flash25Opcode cmd)
00098 {
00099     CS_ENABLE();
00100 
00101     kfile_putc(cmd, channel);
00102 
00103     CS_DISABLE();
00104 }
00105 
00112 static bool flash25_pin_init(void)
00113 {
00114     uint8_t device_id;
00115     uint8_t manufacturer;
00116 
00117     SPI_HW_INIT();
00118 
00119     CS_ENABLE();
00120     /*
00121      * Send read id productor opcode on
00122      * comunication channel
00123      * TODO:controllare se ha senso
00124      */
00125     kfile_putc(FLASH25_RDID, channel);
00126 
00127     manufacturer = kfile_getc(channel);
00128     device_id = kfile_getc(channel);
00129 
00130     CS_DISABLE();
00131 
00132     if((FLASH25_MANUFACTURER_ID == manufacturer) &&
00133         (FLASH25_DEVICE_ID == device_id))
00134         return true;
00135     else
00136         return false;
00137 }
00138 
00146 static KFile * flash25_reopen(struct KFile *fd)
00147 {
00148     KFILE_ASSERT_GENERIC(fd);
00149 
00150     fd->seek_pos = 0;
00151     fd->size = FLASH25_MEM_SIZE;
00152 
00153     kprintf("flash25 file opened\n");
00154     return fd;
00155 }
00156 
00163 static int flash25_close(UNUSED_ARG(struct KFile *,fd))
00164 {
00165     kprintf("flash25 file closed\n");
00166     return 0;
00167 }
00168 
00180 static size_t flash25_read(struct KFile *fd, void *buf, size_t size)
00181 {
00182     uint8_t *data = (uint8_t *)buf;
00183 
00184     KFILE_ASSERT_GENERIC(fd);
00185 
00186     ASSERT(fd->seek_pos + size <= fd->size);
00187     size = MIN((uint32_t)size, fd->size - fd->seek_pos);
00188 
00189     //kprintf("Reading at addr[%lu], size[%d]\n", fd->seek_pos, size);
00190     CS_ENABLE();
00191 
00192     kfile_putc(FLASH25_READ, channel);
00193 
00194 
00195     /*
00196      * Address that we want to read.
00197      */
00198     kfile_putc((fd->seek_pos >> 16) & 0xFF, channel);
00199     kfile_putc((fd->seek_pos >> 8) & 0xFF, channel);
00200     kfile_putc(fd->seek_pos & 0xFF, channel);
00201 
00202     kfile_read(channel, data, size);
00203 
00204     CS_DISABLE();
00205 
00206     fd->seek_pos += size;
00207 
00208     return size;
00209 }
00210 
00230 static size_t flash25_write(struct KFile *fd, const void *_buf, size_t size)
00231 {
00232     flash25Offset_t offset;
00233     flash25Size_t total_write = 0;
00234     flash25Size_t wr_len;
00235     const uint8_t *data = (const uint8_t *) _buf;
00236 
00237     KFILE_ASSERT_GENERIC(fd);
00238     ASSERT(fd->seek_pos + size <= fd->size);
00239 
00240     size = MIN((flash25Size_t)size, fd->size - fd->seek_pos);
00241 
00242     while (size)
00243     {
00244         offset = fd->seek_pos % (flash25Size_t)FLASH25_PAGE_SIZE;
00245         wr_len = MIN((flash25Size_t)size, FLASH25_PAGE_SIZE - (flash25Size_t)offset);
00246 
00247         kprintf("[seek_pos-<%lu>, offset-<%d>]\n", fd->seek_pos, offset);
00248 
00249         /*
00250          * We check serial flash memory state, and wait until ready-flag
00251          * is high.
00252          */
00253         flash25_waitReady();
00254 
00255         /*
00256          * Start write cycle.
00257          * We could write only data not more long than one
00258          * page size.
00259          *
00260          * To write on serial flash memory we must first
00261          * enable write with a WREN opcode command, before
00262          * the PROGRAM opcode.
00263          *
00264          * \note: the same byte cannot be reprogrammed without
00265          * erasing the whole sector first.
00266          */
00267         flash25_sendCmd(FLASH25_WREN);
00268 
00269         CS_ENABLE();
00270         kfile_putc(FLASH25_PROGRAM, channel);
00271 
00272         /*
00273          * Address that we want to write.
00274          */
00275         kfile_putc((fd->seek_pos >> 16) & 0xFF, channel);
00276         kfile_putc((fd->seek_pos >> 8) & 0xFF, channel);
00277         kfile_putc(fd->seek_pos & 0xFF, channel);
00278 
00279         kfile_write(channel, data, wr_len);
00280 
00281         CS_DISABLE();
00282 
00283         data += wr_len;
00284         fd->seek_pos += wr_len;
00285         size -= wr_len;
00286         total_write += wr_len;
00287     }
00288 
00289     kprintf("written %u bytes\n", total_write);
00290     return total_write;
00291 }
00292 
00301 void flash25_sectorErase(Flash25Sector sector)
00302 {
00303 
00304     /*
00305      * Erase a sector could take a while,
00306      * for debug we measure that time
00307      * see datasheet to compare this time.
00308      */
00309     DB(ticks_t start_time = timer_clock());
00310 
00311     CS_ENABLE();
00312 
00313     /*
00314      * To erase a sector of serial flash memory we must first
00315      * enable write with a WREN opcode command, before
00316      * the SECTOR_ERASE opcode. Sector is automatically
00317      * determinate if any address within the sector
00318      * is selected.
00319      */
00320     kfile_putc(FLASH25_WREN, channel);
00321     kfile_putc(FLASH25_SECTORE_ERASE, channel);
00322 
00323     /*
00324      * Address inside the sector that we want to
00325      * erase.
00326      */
00327     kfile_putc(sector, channel);
00328 
00329     CS_DISABLE();
00330 
00331     /*
00332      * We check serial flash memory state, and wait until ready-flag
00333      * is hight.
00334      */
00335     flash25_waitReady();
00336 
00337     DB(kprintf("Erased sector [%d] in %d ms\n", sector, ticks_to_ms(timer_clock() - start_time)));
00338 
00339 }
00340 
00348 void flash25_chipErase(void)
00349 {
00350     /*
00351      * Erase all chip could take a while,
00352      * for debug we measure that time
00353      * see datasheet to compare this time.
00354      */
00355     DB(ticks_t start_time = timer_clock());
00356 
00357     /*
00358      * To erase serial flash memory we must first
00359      * enable write with a WREN opcode command, before
00360      * the CHIP_ERASE opcode.
00361      */
00362     flash25_sendCmd(FLASH25_WREN);
00363     flash25_sendCmd(FLASH25_CHIP_ERASE);
00364 
00365     /*
00366      * We check serial flash memory state, and wait until ready-flag
00367      * is high.
00368      */
00369     flash25_waitReady();
00370 
00371     DB(kprintf("Erased all memory in %d ms\n", ticks_to_ms(timer_clock() - start_time)));
00372 
00373 }
00374 
00378 void flash25_init(struct KFile *fd, struct KFile *_channel)
00379 {
00380      //Set kfile struct type as a generic kfile structure.
00381     DB(fd->_type = KFT_GENERIC);
00382 
00383     // Set up data flash programming functions.
00384     fd->reopen = flash25_reopen;
00385     fd->close = flash25_close;
00386     fd->read = flash25_read;
00387     fd->write = flash25_write;
00388     fd->seek = kfile_genericSeek;
00389 
00390     /*
00391      * Init a local channel structure and flash kfile interface.
00392      */
00393     channel = _channel;
00394     flash25_reopen(fd);
00395 
00396     /*
00397      * Init data flash memory and micro pin.
00398      */
00399     if (!flash25_pin_init())
00400         ASSERT(0);
00401 }
00402 
00403 #if CONFIG_TEST
00404 
00410 bool flash25_test(KFile *channel)
00411 {
00412     KFile fd;
00413     uint8_t test_buf[256];
00414 
00415     /*
00416      * Init a spi kfile interface and
00417      * flash driver.
00418      */
00419     flash25_init(&fd, channel);
00420 
00421     kprintf("Init serial flash\n");
00422 
00423     flash25_chipErase();
00424 
00425     flash25_sectorErase(FLASH25_SECT1);
00426     flash25_sectorErase(FLASH25_SECT2);
00427     flash25_sectorErase(FLASH25_SECT3);
00428     flash25_sectorErase(FLASH25_SECT4);
00429 
00430     /*
00431      * Launche a kfile test interface.
00432      */
00433     kprintf("Kfile test start..\n");
00434     if (!kfile_test(&fd, test_buf, NULL, sizeof(test_buf)))
00435         return false;
00436 
00437     return true;
00438 }
00439 #endif /* CONFIG_TEST */