Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers flash_write.c Source File

flash_write.c

00001 /****************************************************************************
00002  *    Copyright 2010 Andy Kirkham, Stellar Technologies Ltd
00003  *    
00004  *    This file is part of the Satellite Observers Workbench (SOWB).
00005  *
00006  *    SOWB is free software: you can redistribute it and/or modify
00007  *    it under the terms of the GNU General Public License as published by
00008  *    the Free Software Foundation, either version 3 of the License, or
00009  *    (at your option) any later version.
00010  *
00011  *    SOWB is distributed in the hope that it will be useful,
00012  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *    GNU General Public License for more details.
00015  *
00016  *    You should have received a copy of the GNU General Public License
00017  *    along with SOWB.  If not, see <http://www.gnu.org/licenses/>.
00018  *
00019  *    $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $
00020  *    
00021  ***************************************************************************/
00022 
00023 #include "sowb.h"
00024 #include "flash.h"
00025 #include "ssp0.h"
00026 #include "dma.h"
00027 #include "gpio.h"
00028 #include "rit.h"
00029 #include "user.h"
00030 #include "utils.h"
00031 #include "debug.h"
00032 
00033 /* Flags to show what state we are in. */
00034 bool page_write_in_progress = false;
00035 bool page_write_buffer_in_use = false;
00036 
00037 /* Flag used by the flash_erase.c file. */
00038 extern bool sector_erase_in_progress;
00039 
00040 /* Buffer used to hold a copy of the page to write. Used
00041    to ensure the DMA has a valid buffer to copy. */
00042 char flash_page_write_buffer[FLASH_PAGE_SIZE];
00043 
00044 /** flash_write_in_progress
00045  */
00046 bool flash_write_in_progress(void) {
00047     return page_write_in_progress;
00048 }
00049 
00050 /** flash_page_write
00051  */
00052 int flash_page_write(int page, char *buffer) {
00053     
00054     /* Wait for the write page buffer to be released by
00055        the DMA ISR handler, if in use, then make a copy
00056        of the source buffer for the DMA. */
00057     while (page_write_buffer_in_use) WHILE_WAITING_DO_PROCESS_FUNCTIONS;
00058     memcpy(flash_page_write_buffer, buffer, FLASH_PAGE_SIZE);
00059     page_write_buffer_in_use = true;
00060 
00061     
00062     /* Below this we check for conditions that should stall 
00063        us before continuing. However, sector erase is different,
00064        it can take quite some time to complete. If this is the
00065        case, rather than block (wait), we'll return zero (not
00066        done) and allow the caller to schedule a write later. */
00067     if (sector_erase_in_progress) return 0;
00068     
00069     /* Do not start a page write while another page write
00070        is in progress. This flag is released by the RIT
00071        timer callback when the WIP flag shows a previous
00072        write has completed. */    
00073     while(page_write_in_progress) WHILE_WAITING_DO_PROCESS_FUNCTIONS;
00074 
00075     /* Do not start a page write while a page read is in operation. */
00076     while (flash_read_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS;
00077 
00078     /* Request DMA channel0. */
00079     while(!DMA_request_channel(0)) WHILE_WAITING_DO_PROCESS_FUNCTIONS;
00080     
00081     /* Request the use of SSP0. */
00082     while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS;
00083     
00084     /* Flag a write is in progress. */    
00085     page_write_in_progress = true;
00086     
00087     /* Switch on WIP/WEL. */
00088     FLASH_CS_ASSERT;       
00089     FLASH_SHORT_COMMAND(FLASH_WREN);        
00090     FLASH_CS_DEASSERT;
00091 
00092     /* Originally I dropped into a do { ... } while(); here but
00093        found the time between the CS deassert and reassert inside
00094        the loop was *very* short and the flash device wasn't to
00095        keen on this. So, I switched to a "flush rx fifo" and the
00096        use a while() { ... } loop, just puts some delay between
00097        the CS manipulation. */
00098     SSP0_FLUSH_RX_FIFO;
00099     
00100     /* Wait until the flash device has the WEL bit on. */
00101     while ((LPC_SSP0->DR & 0x2) == 0) {            
00102         FLASH_CS_ASSERT;
00103         FLASH_SHORT_COMMAND(FLASH_RDSR);
00104         SSP0_FLUSH_RX_FIFO;
00105         SSP0_WRITE_BYTE(0);
00106         while (SSP0_IS_BUSY);
00107         FLASH_CS_DEASSERT;
00108     }
00109     
00110     FLASH_CS_ASSERT;
00111     FLASH_LONG_COMMAND(FLASH_PP, page); 
00112 
00113     LPC_GPDMA->DMACIntTCClear = 0x1;
00114     LPC_GPDMA->DMACSoftSReq   = 0xC;
00115         
00116     /* Prep Channel0 to send the buffer to the flash device. */
00117     LPC_GPDMACH0->DMACCSrcAddr  = (uint32_t)flash_page_write_buffer;
00118     LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR;
00119     LPC_GPDMACH0->DMACCLLI      = 0;
00120     LPC_GPDMACH0->DMACCControl  = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | (uint32_t)FLASH_PAGE_SIZE;
00121     
00122     /* Enable SSP0 DMA. */
00123     LPC_SSP0->DMACR = 0x2;
00124 
00125     /* Enable Channel0 */
00126     LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | 
00127                                 DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX | 
00128                                 DMA_TRANSFER_TYPE_M2P |
00129                                 DMA_MASK_IE |
00130                                 DMA_MASK_ITC;
00131     
00132                                 
00133     /* SSP0 CS line and "page_write_in_progress" flag are now 
00134        under DMA/SSP0 interrupt control. See ISR handlers for 
00135        more information. */
00136        
00137     return 1;
00138 }
00139 
00140 /** _flash_write_timer_callback
00141  *
00142  * RIT timer callback.
00143  *
00144  * After the write operation is complete this callback
00145  * is used to examine the WIP flag in the flash status
00146  * register. If it's still set then we reset the timer
00147  * and try again in the future. If it's clear then we
00148  * can mark the process as complete.
00149  *
00150  * @param int index The index of the timer the RIT modulr used.
00151  */
00152 void _flash_write_timer_callback(int index) {
00153     uint32_t sr = 1;
00154     
00155     /* Read the WIP flag from the flash device status
00156        register and if the write cycle is complete mark
00157        the operation as complete. Otherwise, reset the
00158        timer to test again in the future. */
00159     FLASH_CS_ASSERT;
00160     FLASH_SHORT_COMMAND(FLASH_RDSR);
00161     SSP0_WRITE_BYTE(0);
00162     while (SSP0_IS_BUSY);
00163     FLASH_CS_DEASSERT;
00164     while(LPC_SSP0->SR & (1UL << 2)) {
00165         /* This loop ensures we read the last byte in the
00166            RX FIFO and test that. */
00167         sr = LPC_SSP0->DR;
00168     }
00169     if (sr & 0x1) {
00170         if (sector_erase_in_progress) rit_timer_set_counter(index, 100);
00171         else rit_timer_set_counter(index, FLASH_WIP_TEST_TIME);
00172     }
00173     else {
00174         FLASH_CS_ASSERT;
00175         FLASH_SHORT_COMMAND(FLASH_WRDI);
00176         SSP0_FLUSH_RX_FIFO;
00177         FLASH_CS_DEASSERT;
00178         if (sector_erase_in_progress) sector_erase_in_progress = false;
00179         if (page_write_in_progress)   page_write_in_progress = false;
00180         SSP0_release();
00181     }
00182 }
00183 
00184 /** flash_write_dma0_irq
00185  *
00186  * DMA transfer irq callback. 
00187  */
00188 int flash_write_dma0_irq(int channel) {
00189     int rval = 0;
00190     
00191     /* If we were using DMA to transfer our buffer to the flash
00192        device then mark the buffer as "released" and no longer 
00193        in use, release the DMA channel and start the "detect WIP
00194        indicates complete" timer. */
00195     if (page_write_buffer_in_use) {
00196         page_write_buffer_in_use = false;
00197         LPC_GPDMACH0->DMACCConfig = 0;
00198         DMA_release_channel(0);
00199         LPC_SSP0->IMSC = (1UL << 3);
00200         rit_timer_set_counter(FLASH_WRITE_CB, FLASH_WIP_TEST_TIME);
00201         rval = 1;
00202     }
00203         
00204     return rval;
00205 }
00206 
00207 /** flash_read_ssp0_irq
00208  * 
00209  * Called by the SSP0 ISR handler.
00210  */
00211 int flash_write_ssp0_irq(void) {
00212     if (page_write_in_progress) {
00213         if (LPC_SSP0->MIS & (1UL << 3)) {
00214             LPC_SSP0->IMSC &= ~(1UL << 3); 
00215             while(SSP0_IS_BUSY);            
00216             FLASH_CS_DEASSERT;            
00217             SSP0_release();
00218             return 1;
00219         }
00220     }
00221     return 0;
00222 }
00223 
00224