Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.
flash/flash_write.c@0:0a841b89d614, 2010-10-11 (annotated)
- Committer:
- AjK
- Date:
- Mon Oct 11 10:34:55 2010 +0000
- Revision:
- 0:0a841b89d614
Totally Alpha quality as this project isn\t completed. Just publishing it as it answers many questions asked in the forums
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AjK | 0:0a841b89d614 | 1 | /**************************************************************************** |
AjK | 0:0a841b89d614 | 2 | * Copyright 2010 Andy Kirkham, Stellar Technologies Ltd |
AjK | 0:0a841b89d614 | 3 | * |
AjK | 0:0a841b89d614 | 4 | * This file is part of the Satellite Observers Workbench (SOWB). |
AjK | 0:0a841b89d614 | 5 | * |
AjK | 0:0a841b89d614 | 6 | * SOWB is free software: you can redistribute it and/or modify |
AjK | 0:0a841b89d614 | 7 | * it under the terms of the GNU General Public License as published by |
AjK | 0:0a841b89d614 | 8 | * the Free Software Foundation, either version 3 of the License, or |
AjK | 0:0a841b89d614 | 9 | * (at your option) any later version. |
AjK | 0:0a841b89d614 | 10 | * |
AjK | 0:0a841b89d614 | 11 | * SOWB is distributed in the hope that it will be useful, |
AjK | 0:0a841b89d614 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
AjK | 0:0a841b89d614 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
AjK | 0:0a841b89d614 | 14 | * GNU General Public License for more details. |
AjK | 0:0a841b89d614 | 15 | * |
AjK | 0:0a841b89d614 | 16 | * You should have received a copy of the GNU General Public License |
AjK | 0:0a841b89d614 | 17 | * along with SOWB. If not, see <http://www.gnu.org/licenses/>. |
AjK | 0:0a841b89d614 | 18 | * |
AjK | 0:0a841b89d614 | 19 | * $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $ |
AjK | 0:0a841b89d614 | 20 | * |
AjK | 0:0a841b89d614 | 21 | ***************************************************************************/ |
AjK | 0:0a841b89d614 | 22 | |
AjK | 0:0a841b89d614 | 23 | #include "sowb.h" |
AjK | 0:0a841b89d614 | 24 | #include "flash.h" |
AjK | 0:0a841b89d614 | 25 | #include "ssp0.h" |
AjK | 0:0a841b89d614 | 26 | #include "dma.h" |
AjK | 0:0a841b89d614 | 27 | #include "gpio.h" |
AjK | 0:0a841b89d614 | 28 | #include "rit.h" |
AjK | 0:0a841b89d614 | 29 | #include "user.h" |
AjK | 0:0a841b89d614 | 30 | #include "utils.h" |
AjK | 0:0a841b89d614 | 31 | #include "debug.h" |
AjK | 0:0a841b89d614 | 32 | |
AjK | 0:0a841b89d614 | 33 | /* Flags to show what state we are in. */ |
AjK | 0:0a841b89d614 | 34 | bool page_write_in_progress = false; |
AjK | 0:0a841b89d614 | 35 | bool page_write_buffer_in_use = false; |
AjK | 0:0a841b89d614 | 36 | |
AjK | 0:0a841b89d614 | 37 | /* Flag used by the flash_erase.c file. */ |
AjK | 0:0a841b89d614 | 38 | extern bool sector_erase_in_progress; |
AjK | 0:0a841b89d614 | 39 | |
AjK | 0:0a841b89d614 | 40 | /* Buffer used to hold a copy of the page to write. Used |
AjK | 0:0a841b89d614 | 41 | to ensure the DMA has a valid buffer to copy. */ |
AjK | 0:0a841b89d614 | 42 | char flash_page_write_buffer[FLASH_PAGE_SIZE]; |
AjK | 0:0a841b89d614 | 43 | |
AjK | 0:0a841b89d614 | 44 | /** flash_write_in_progress |
AjK | 0:0a841b89d614 | 45 | */ |
AjK | 0:0a841b89d614 | 46 | bool flash_write_in_progress(void) { |
AjK | 0:0a841b89d614 | 47 | return page_write_in_progress; |
AjK | 0:0a841b89d614 | 48 | } |
AjK | 0:0a841b89d614 | 49 | |
AjK | 0:0a841b89d614 | 50 | /** flash_page_write |
AjK | 0:0a841b89d614 | 51 | */ |
AjK | 0:0a841b89d614 | 52 | int flash_page_write(int page, char *buffer) { |
AjK | 0:0a841b89d614 | 53 | |
AjK | 0:0a841b89d614 | 54 | /* Wait for the write page buffer to be released by |
AjK | 0:0a841b89d614 | 55 | the DMA ISR handler, if in use, then make a copy |
AjK | 0:0a841b89d614 | 56 | of the source buffer for the DMA. */ |
AjK | 0:0a841b89d614 | 57 | while (page_write_buffer_in_use) WHILE_WAITING_DO_PROCESS_FUNCTIONS; |
AjK | 0:0a841b89d614 | 58 | memcpy(flash_page_write_buffer, buffer, FLASH_PAGE_SIZE); |
AjK | 0:0a841b89d614 | 59 | page_write_buffer_in_use = true; |
AjK | 0:0a841b89d614 | 60 | |
AjK | 0:0a841b89d614 | 61 | |
AjK | 0:0a841b89d614 | 62 | /* Below this we check for conditions that should stall |
AjK | 0:0a841b89d614 | 63 | us before continuing. However, sector erase is different, |
AjK | 0:0a841b89d614 | 64 | it can take quite some time to complete. If this is the |
AjK | 0:0a841b89d614 | 65 | case, rather than block (wait), we'll return zero (not |
AjK | 0:0a841b89d614 | 66 | done) and allow the caller to schedule a write later. */ |
AjK | 0:0a841b89d614 | 67 | if (sector_erase_in_progress) return 0; |
AjK | 0:0a841b89d614 | 68 | |
AjK | 0:0a841b89d614 | 69 | /* Do not start a page write while another page write |
AjK | 0:0a841b89d614 | 70 | is in progress. This flag is released by the RIT |
AjK | 0:0a841b89d614 | 71 | timer callback when the WIP flag shows a previous |
AjK | 0:0a841b89d614 | 72 | write has completed. */ |
AjK | 0:0a841b89d614 | 73 | while(page_write_in_progress) WHILE_WAITING_DO_PROCESS_FUNCTIONS; |
AjK | 0:0a841b89d614 | 74 | |
AjK | 0:0a841b89d614 | 75 | /* Do not start a page write while a page read is in operation. */ |
AjK | 0:0a841b89d614 | 76 | while (flash_read_in_progress()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; |
AjK | 0:0a841b89d614 | 77 | |
AjK | 0:0a841b89d614 | 78 | /* Request DMA channel0. */ |
AjK | 0:0a841b89d614 | 79 | while(!DMA_request_channel(0)) WHILE_WAITING_DO_PROCESS_FUNCTIONS; |
AjK | 0:0a841b89d614 | 80 | |
AjK | 0:0a841b89d614 | 81 | /* Request the use of SSP0. */ |
AjK | 0:0a841b89d614 | 82 | while(!SSP0_request()) WHILE_WAITING_DO_PROCESS_FUNCTIONS; |
AjK | 0:0a841b89d614 | 83 | |
AjK | 0:0a841b89d614 | 84 | /* Flag a write is in progress. */ |
AjK | 0:0a841b89d614 | 85 | page_write_in_progress = true; |
AjK | 0:0a841b89d614 | 86 | |
AjK | 0:0a841b89d614 | 87 | /* Switch on WIP/WEL. */ |
AjK | 0:0a841b89d614 | 88 | FLASH_CS_ASSERT; |
AjK | 0:0a841b89d614 | 89 | FLASH_SHORT_COMMAND(FLASH_WREN); |
AjK | 0:0a841b89d614 | 90 | FLASH_CS_DEASSERT; |
AjK | 0:0a841b89d614 | 91 | |
AjK | 0:0a841b89d614 | 92 | /* Originally I dropped into a do { ... } while(); here but |
AjK | 0:0a841b89d614 | 93 | found the time between the CS deassert and reassert inside |
AjK | 0:0a841b89d614 | 94 | the loop was *very* short and the flash device wasn't to |
AjK | 0:0a841b89d614 | 95 | keen on this. So, I switched to a "flush rx fifo" and the |
AjK | 0:0a841b89d614 | 96 | use a while() { ... } loop, just puts some delay between |
AjK | 0:0a841b89d614 | 97 | the CS manipulation. */ |
AjK | 0:0a841b89d614 | 98 | SSP0_FLUSH_RX_FIFO; |
AjK | 0:0a841b89d614 | 99 | |
AjK | 0:0a841b89d614 | 100 | /* Wait until the flash device has the WEL bit on. */ |
AjK | 0:0a841b89d614 | 101 | while ((LPC_SSP0->DR & 0x2) == 0) { |
AjK | 0:0a841b89d614 | 102 | FLASH_CS_ASSERT; |
AjK | 0:0a841b89d614 | 103 | FLASH_SHORT_COMMAND(FLASH_RDSR); |
AjK | 0:0a841b89d614 | 104 | SSP0_FLUSH_RX_FIFO; |
AjK | 0:0a841b89d614 | 105 | SSP0_WRITE_BYTE(0); |
AjK | 0:0a841b89d614 | 106 | while (SSP0_IS_BUSY); |
AjK | 0:0a841b89d614 | 107 | FLASH_CS_DEASSERT; |
AjK | 0:0a841b89d614 | 108 | } |
AjK | 0:0a841b89d614 | 109 | |
AjK | 0:0a841b89d614 | 110 | FLASH_CS_ASSERT; |
AjK | 0:0a841b89d614 | 111 | FLASH_LONG_COMMAND(FLASH_PP, page); |
AjK | 0:0a841b89d614 | 112 | |
AjK | 0:0a841b89d614 | 113 | LPC_GPDMA->DMACIntTCClear = 0x1; |
AjK | 0:0a841b89d614 | 114 | LPC_GPDMA->DMACSoftSReq = 0xC; |
AjK | 0:0a841b89d614 | 115 | |
AjK | 0:0a841b89d614 | 116 | /* Prep Channel0 to send the buffer to the flash device. */ |
AjK | 0:0a841b89d614 | 117 | LPC_GPDMACH0->DMACCSrcAddr = (uint32_t)flash_page_write_buffer; |
AjK | 0:0a841b89d614 | 118 | LPC_GPDMACH0->DMACCDestAddr = (uint32_t)&LPC_SSP0->DR; |
AjK | 0:0a841b89d614 | 119 | LPC_GPDMACH0->DMACCLLI = 0; |
AjK | 0:0a841b89d614 | 120 | LPC_GPDMACH0->DMACCControl = DMA_CHANNEL_TCIE | DMA_CHANNEL_SRC_INC | (uint32_t)FLASH_PAGE_SIZE; |
AjK | 0:0a841b89d614 | 121 | |
AjK | 0:0a841b89d614 | 122 | /* Enable SSP0 DMA. */ |
AjK | 0:0a841b89d614 | 123 | LPC_SSP0->DMACR = 0x2; |
AjK | 0:0a841b89d614 | 124 | |
AjK | 0:0a841b89d614 | 125 | /* Enable Channel0 */ |
AjK | 0:0a841b89d614 | 126 | LPC_GPDMACH0->DMACCConfig = DMA_CHANNEL_ENABLE | |
AjK | 0:0a841b89d614 | 127 | DMA_CHANNEL_DST_PERIPHERAL_SSP0_TX | |
AjK | 0:0a841b89d614 | 128 | DMA_TRANSFER_TYPE_M2P | |
AjK | 0:0a841b89d614 | 129 | DMA_MASK_IE | |
AjK | 0:0a841b89d614 | 130 | DMA_MASK_ITC; |
AjK | 0:0a841b89d614 | 131 | |
AjK | 0:0a841b89d614 | 132 | |
AjK | 0:0a841b89d614 | 133 | /* SSP0 CS line and "page_write_in_progress" flag are now |
AjK | 0:0a841b89d614 | 134 | under DMA/SSP0 interrupt control. See ISR handlers for |
AjK | 0:0a841b89d614 | 135 | more information. */ |
AjK | 0:0a841b89d614 | 136 | |
AjK | 0:0a841b89d614 | 137 | return 1; |
AjK | 0:0a841b89d614 | 138 | } |
AjK | 0:0a841b89d614 | 139 | |
AjK | 0:0a841b89d614 | 140 | /** _flash_write_timer_callback |
AjK | 0:0a841b89d614 | 141 | * |
AjK | 0:0a841b89d614 | 142 | * RIT timer callback. |
AjK | 0:0a841b89d614 | 143 | * |
AjK | 0:0a841b89d614 | 144 | * After the write operation is complete this callback |
AjK | 0:0a841b89d614 | 145 | * is used to examine the WIP flag in the flash status |
AjK | 0:0a841b89d614 | 146 | * register. If it's still set then we reset the timer |
AjK | 0:0a841b89d614 | 147 | * and try again in the future. If it's clear then we |
AjK | 0:0a841b89d614 | 148 | * can mark the process as complete. |
AjK | 0:0a841b89d614 | 149 | * |
AjK | 0:0a841b89d614 | 150 | * @param int index The index of the timer the RIT modulr used. |
AjK | 0:0a841b89d614 | 151 | */ |
AjK | 0:0a841b89d614 | 152 | void _flash_write_timer_callback(int index) { |
AjK | 0:0a841b89d614 | 153 | uint32_t sr = 1; |
AjK | 0:0a841b89d614 | 154 | |
AjK | 0:0a841b89d614 | 155 | /* Read the WIP flag from the flash device status |
AjK | 0:0a841b89d614 | 156 | register and if the write cycle is complete mark |
AjK | 0:0a841b89d614 | 157 | the operation as complete. Otherwise, reset the |
AjK | 0:0a841b89d614 | 158 | timer to test again in the future. */ |
AjK | 0:0a841b89d614 | 159 | FLASH_CS_ASSERT; |
AjK | 0:0a841b89d614 | 160 | FLASH_SHORT_COMMAND(FLASH_RDSR); |
AjK | 0:0a841b89d614 | 161 | SSP0_WRITE_BYTE(0); |
AjK | 0:0a841b89d614 | 162 | while (SSP0_IS_BUSY); |
AjK | 0:0a841b89d614 | 163 | FLASH_CS_DEASSERT; |
AjK | 0:0a841b89d614 | 164 | while(LPC_SSP0->SR & (1UL << 2)) { |
AjK | 0:0a841b89d614 | 165 | /* This loop ensures we read the last byte in the |
AjK | 0:0a841b89d614 | 166 | RX FIFO and test that. */ |
AjK | 0:0a841b89d614 | 167 | sr = LPC_SSP0->DR; |
AjK | 0:0a841b89d614 | 168 | } |
AjK | 0:0a841b89d614 | 169 | if (sr & 0x1) { |
AjK | 0:0a841b89d614 | 170 | if (sector_erase_in_progress) rit_timer_set_counter(index, 100); |
AjK | 0:0a841b89d614 | 171 | else rit_timer_set_counter(index, FLASH_WIP_TEST_TIME); |
AjK | 0:0a841b89d614 | 172 | } |
AjK | 0:0a841b89d614 | 173 | else { |
AjK | 0:0a841b89d614 | 174 | FLASH_CS_ASSERT; |
AjK | 0:0a841b89d614 | 175 | FLASH_SHORT_COMMAND(FLASH_WRDI); |
AjK | 0:0a841b89d614 | 176 | SSP0_FLUSH_RX_FIFO; |
AjK | 0:0a841b89d614 | 177 | FLASH_CS_DEASSERT; |
AjK | 0:0a841b89d614 | 178 | if (sector_erase_in_progress) sector_erase_in_progress = false; |
AjK | 0:0a841b89d614 | 179 | if (page_write_in_progress) page_write_in_progress = false; |
AjK | 0:0a841b89d614 | 180 | SSP0_release(); |
AjK | 0:0a841b89d614 | 181 | } |
AjK | 0:0a841b89d614 | 182 | } |
AjK | 0:0a841b89d614 | 183 | |
AjK | 0:0a841b89d614 | 184 | /** flash_write_dma0_irq |
AjK | 0:0a841b89d614 | 185 | * |
AjK | 0:0a841b89d614 | 186 | * DMA transfer irq callback. |
AjK | 0:0a841b89d614 | 187 | */ |
AjK | 0:0a841b89d614 | 188 | int flash_write_dma0_irq(int channel) { |
AjK | 0:0a841b89d614 | 189 | int rval = 0; |
AjK | 0:0a841b89d614 | 190 | |
AjK | 0:0a841b89d614 | 191 | /* If we were using DMA to transfer our buffer to the flash |
AjK | 0:0a841b89d614 | 192 | device then mark the buffer as "released" and no longer |
AjK | 0:0a841b89d614 | 193 | in use, release the DMA channel and start the "detect WIP |
AjK | 0:0a841b89d614 | 194 | indicates complete" timer. */ |
AjK | 0:0a841b89d614 | 195 | if (page_write_buffer_in_use) { |
AjK | 0:0a841b89d614 | 196 | page_write_buffer_in_use = false; |
AjK | 0:0a841b89d614 | 197 | LPC_GPDMACH0->DMACCConfig = 0; |
AjK | 0:0a841b89d614 | 198 | DMA_release_channel(0); |
AjK | 0:0a841b89d614 | 199 | LPC_SSP0->IMSC = (1UL << 3); |
AjK | 0:0a841b89d614 | 200 | rit_timer_set_counter(FLASH_WRITE_CB, FLASH_WIP_TEST_TIME); |
AjK | 0:0a841b89d614 | 201 | rval = 1; |
AjK | 0:0a841b89d614 | 202 | } |
AjK | 0:0a841b89d614 | 203 | |
AjK | 0:0a841b89d614 | 204 | return rval; |
AjK | 0:0a841b89d614 | 205 | } |
AjK | 0:0a841b89d614 | 206 | |
AjK | 0:0a841b89d614 | 207 | /** flash_read_ssp0_irq |
AjK | 0:0a841b89d614 | 208 | * |
AjK | 0:0a841b89d614 | 209 | * Called by the SSP0 ISR handler. |
AjK | 0:0a841b89d614 | 210 | */ |
AjK | 0:0a841b89d614 | 211 | int flash_write_ssp0_irq(void) { |
AjK | 0:0a841b89d614 | 212 | if (page_write_in_progress) { |
AjK | 0:0a841b89d614 | 213 | if (LPC_SSP0->MIS & (1UL << 3)) { |
AjK | 0:0a841b89d614 | 214 | LPC_SSP0->IMSC &= ~(1UL << 3); |
AjK | 0:0a841b89d614 | 215 | while(SSP0_IS_BUSY); |
AjK | 0:0a841b89d614 | 216 | FLASH_CS_DEASSERT; |
AjK | 0:0a841b89d614 | 217 | SSP0_release(); |
AjK | 0:0a841b89d614 | 218 | return 1; |
AjK | 0:0a841b89d614 | 219 | } |
AjK | 0:0a841b89d614 | 220 | } |
AjK | 0:0a841b89d614 | 221 | return 0; |
AjK | 0:0a841b89d614 | 222 | } |
AjK | 0:0a841b89d614 | 223 | |
AjK | 0:0a841b89d614 | 224 |