BeRTOS
flash25.c
Go to the documentation of this file.
00001 
00042 /*
00043  * We use a spi bus, thus include hardware specific definition.
00044  * If you use another channel you must redefine this macros.
00045  */
00046 #include "hw/hw_spi.h"
00047 
00048 #include <cfg/macros.h>
00049 #include <cfg/debug.h>
00050 
00051 #include <drv/timer.h>
00052 #include <drv/flash25.h>
00053 
00054 #include <io/kfile.h>
00055 
00056 #include <cpu/power.h> /* cpu_relax() */
00057 
00058 #warning FIXME:This file was changed, but is untested!
00059 
00063 static void flash25_waitReady(Flash25 *fd)
00064 {
00065     uint8_t stat;
00066 
00067     while (1)
00068     {
00069         CS_ENABLE();
00070 
00071         kfile_putc(FLASH25_RDSR, fd->channel);
00072         stat = kfile_getc(fd->channel);
00073 
00074         CS_DISABLE();
00075 
00076         if (!(stat & RDY_BIT))
00077             break;
00078 
00079         cpu_relax();
00080     }
00081 }
00082 
00086 static void flash25_sendCmd(Flash25 *fd, Flash25Opcode cmd)
00087 {
00088     CS_ENABLE();
00089 
00090     kfile_putc(cmd, fd->channel);
00091 
00092     CS_DISABLE();
00093 }
00094 
00101 static bool flash25_pin_init(Flash25 *fd)
00102 {
00103     uint8_t device_id;
00104     uint8_t manufacturer;
00105 
00106     SPI_HW_INIT();
00107 
00108     CS_ENABLE();
00109     /*
00110      * Send read id productor opcode on
00111      * comunication channel
00112      * TODO:controllare se ha senso
00113      */
00114     kfile_putc(FLASH25_RDID, fd->channel);
00115 
00116     manufacturer = kfile_getc(fd->channel);
00117     device_id = kfile_getc(fd->channel);
00118 
00119     CS_DISABLE();
00120 
00121     if((FLASH25_MANUFACTURER_ID == manufacturer) &&
00122         (FLASH25_DEVICE_ID == device_id))
00123         return true;
00124     else
00125         return false;
00126 }
00127 
00135 static KFile * flash25_reopen(struct KFile *_fd)
00136 {
00137     Flash25 *fd = FLASH25_CAST(_fd);
00138 
00139     fd->fd.seek_pos = 0;
00140     fd->fd.size = FLASH25_MEM_SIZE;
00141 
00142     kprintf("flash25 file opened\n");
00143     return &fd->fd;
00144 }
00145 
00152 static int flash25_close(UNUSED_ARG(struct KFile *,fd))
00153 {
00154     kprintf("flash25 file closed\n");
00155     return 0;
00156 }
00157 
00169 static size_t flash25_read(struct KFile *_fd, void *buf, size_t size)
00170 {
00171     uint8_t *data = (uint8_t *)buf;
00172 
00173     Flash25 *fd = FLASH25_CAST(_fd);
00174 
00175     ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= fd->fd.size);
00176     size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00177 
00178     //kprintf("Reading at addr[%lu], size[%d]\n", fd->seek_pos, size);
00179     CS_ENABLE();
00180 
00181     kfile_putc(FLASH25_READ, fd->channel);
00182 
00183 
00184     /*
00185      * Address that we want to read.
00186      */
00187     kfile_putc((fd->fd.seek_pos >> 16) & 0xFF, fd->channel);
00188     kfile_putc((fd->fd.seek_pos >> 8) & 0xFF, fd->channel);
00189     kfile_putc(fd->fd.seek_pos & 0xFF, fd->channel);
00190 
00191     kfile_read(fd->channel, data, size);
00192 
00193     CS_DISABLE();
00194 
00195     fd->fd.seek_pos += size;
00196 
00197     return size;
00198 }
00199 
00219 static size_t flash25_write(struct KFile *_fd, const void *_buf, size_t size)
00220 {
00221     flash25Offset_t offset;
00222     flash25Size_t total_write = 0;
00223     flash25Size_t wr_len;
00224     const uint8_t *data = (const uint8_t *) _buf;
00225 
00226     Flash25 *fd = FLASH25_CAST(_fd);
00227 
00228     ASSERT(fd->fd.seek_pos + (kfile_off_t)size <= fd->fd.size);
00229 
00230     size = MIN((kfile_off_t)size, fd->fd.size - fd->fd.seek_pos);
00231 
00232     while (size)
00233     {
00234         offset = fd->fd.seek_pos % (flash25Size_t)FLASH25_PAGE_SIZE;
00235         wr_len = MIN((flash25Size_t)size, FLASH25_PAGE_SIZE - (flash25Size_t)offset);
00236 
00237         kprintf("[seek_pos-<%lu>, offset-<%d>]\n", fd->fd.seek_pos, offset);
00238 
00239         /*
00240          * We check serial flash memory state, and wait until ready-flag
00241          * is high.
00242          */
00243         flash25_waitReady(fd);
00244 
00245         /*
00246          * Start write cycle.
00247          * We could write only data not more long than one
00248          * page size.
00249          *
00250          * To write on serial flash memory we must first
00251          * enable write with a WREN opcode command, before
00252          * the PROGRAM opcode.
00253          *
00254          * \note: the same byte cannot be reprogrammed without
00255          * erasing the whole sector first.
00256          */
00257         flash25_sendCmd(fd, FLASH25_WREN);
00258 
00259         CS_ENABLE();
00260         kfile_putc(FLASH25_PROGRAM, fd->channel);
00261 
00262         /*
00263          * Address that we want to write.
00264          */
00265         kfile_putc((fd->fd.seek_pos >> 16) & 0xFF, fd->channel);
00266         kfile_putc((fd->fd.seek_pos >> 8) & 0xFF, fd->channel);
00267         kfile_putc(fd->fd.seek_pos & 0xFF, fd->channel);
00268 
00269         kfile_write(fd->channel, data, wr_len);
00270 
00271         CS_DISABLE();
00272 
00273         data += wr_len;
00274         fd->fd.seek_pos += wr_len;
00275         size -= wr_len;
00276         total_write += wr_len;
00277     }
00278 
00279     kprintf("written %lu bytes\n", total_write);
00280     return total_write;
00281 }
00282 
00291 void flash25_sectorErase(Flash25 *fd, Flash25Sector sector)
00292 {
00293 
00294     /*
00295      * Erase a sector could take a while,
00296      * for debug we measure that time
00297      * see datasheet to compare this time.
00298      */
00299     DB(ticks_t start_time = timer_clock());
00300 
00301     CS_ENABLE();
00302 
00303     /*
00304      * To erase a sector of serial flash memory we must first
00305      * enable write with a WREN opcode command, before
00306      * the SECTOR_ERASE opcode. Sector is automatically
00307      * determinate if any address within the sector
00308      * is selected.
00309      */
00310     kfile_putc(FLASH25_WREN, fd->channel);
00311     kfile_putc(FLASH25_SECTORE_ERASE,fd-> channel);
00312 
00313     /*
00314      * Address inside the sector that we want to
00315      * erase.
00316      */
00317     kfile_putc(sector, fd->channel);
00318 
00319     CS_DISABLE();
00320 
00321     /*
00322      * We check serial flash memory state, and wait until ready-flag
00323      * is hight.
00324      */
00325     flash25_waitReady(fd);
00326 
00327     DB(kprintf("Erased sector [%ld] in %ld ms\n", (unsigned long)sector, (unsigned long)ticks_to_ms(timer_clock() - start_time)));
00328 }
00329 
00337 void flash25_chipErase(Flash25 *fd)
00338 {
00339     /*
00340      * Erase all chip could take a while,
00341      * for debug we measure that time
00342      * see datasheet to compare this time.
00343      */
00344     DB(ticks_t start_time = timer_clock());
00345 
00346     /*
00347      * To erase serial flash memory we must first
00348      * enable write with a WREN opcode command, before
00349      * the CHIP_ERASE opcode.
00350      */
00351     flash25_sendCmd(fd, FLASH25_WREN);
00352     flash25_sendCmd(fd, FLASH25_CHIP_ERASE);
00353 
00354     /*
00355      * We check serial flash memory state, and wait until ready-flag
00356      * is high.
00357      */
00358     flash25_waitReady(fd);
00359 
00360     DB(kprintf("Erased all memory in %ld ms\n", ticks_to_ms(timer_clock() - start_time)));
00361 
00362 }
00363 
00367 void flash25_init(Flash25 *fd, KFile *ch)
00368 {
00369 
00370     ASSERT(fd);
00371     ASSERT(ch);
00372 
00373      //Set kfile struct type as a generic kfile structure.
00374     DB(fd->fd._type = KFT_FLASH25);
00375 
00376     // Set up data flash programming functions.
00377     fd->fd.reopen = flash25_reopen;
00378     fd->fd.close = flash25_close;
00379     fd->fd.read = flash25_read;
00380     fd->fd.write = flash25_write;
00381     fd->fd.seek = kfile_genericSeek;
00382 
00383     /*
00384      * Init a local channel structure and flash kfile interface.
00385      */
00386     fd->channel = ch;
00387     flash25_reopen(&fd->fd);
00388 
00389     /*
00390      * Init data flash memory and micro pin.
00391      */
00392     if (!flash25_pin_init(fd))
00393         ASSERT(0);
00394 }
00395 
00396