A board support package for the LPC4088 Display Module.
Dependencies: DM_HttpServer DM_USBHost
Dependents: lpc4088_displaymodule_emwin lpc4088_displaymodule_demo_sphere sampleGUI sampleEmptyGUI ... more
Fork of DMSupport by
Memory/SPIFI.cpp@3:2fa7755f2cef, 2014-12-03 (annotated)
- Committer:
- embeddedartists
- Date:
- Wed Dec 03 16:17:10 2014 +0000
- Revision:
- 3:2fa7755f2cef
- Parent:
- 0:6b68dac0d986
- Child:
- 9:a33326afd686
Corrected the SPIFI initialization so that it can run at max speed (i.e. 60MHz). Updated used libraries including the Keyboard, Mouse and Hub changes for USB Host.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
embeddedartists | 0:6b68dac0d986 | 1 | /* |
embeddedartists | 0:6b68dac0d986 | 2 | * Copyright 2013 Embedded Artists AB |
embeddedartists | 0:6b68dac0d986 | 3 | * |
embeddedartists | 0:6b68dac0d986 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
embeddedartists | 0:6b68dac0d986 | 5 | * you may not use this file except in compliance with the License. |
embeddedartists | 0:6b68dac0d986 | 6 | * You may obtain a copy of the License at |
embeddedartists | 0:6b68dac0d986 | 7 | * |
embeddedartists | 0:6b68dac0d986 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
embeddedartists | 0:6b68dac0d986 | 9 | * |
embeddedartists | 0:6b68dac0d986 | 10 | * Unless required by applicable law or agreed to in writing, software |
embeddedartists | 0:6b68dac0d986 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
embeddedartists | 0:6b68dac0d986 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
embeddedartists | 0:6b68dac0d986 | 13 | * See the License for the specific language governing permissions and |
embeddedartists | 0:6b68dac0d986 | 14 | * limitations under the License. |
embeddedartists | 0:6b68dac0d986 | 15 | */ |
embeddedartists | 0:6b68dac0d986 | 16 | |
embeddedartists | 0:6b68dac0d986 | 17 | #include "SPIFI.h" |
embeddedartists | 0:6b68dac0d986 | 18 | #include "mbed_debug.h" |
embeddedartists | 0:6b68dac0d986 | 19 | |
embeddedartists | 0:6b68dac0d986 | 20 | |
embeddedartists | 0:6b68dac0d986 | 21 | /****************************************************************************** |
embeddedartists | 0:6b68dac0d986 | 22 | * Defines and typedefs |
embeddedartists | 0:6b68dac0d986 | 23 | *****************************************************************************/ |
embeddedartists | 0:6b68dac0d986 | 24 | |
embeddedartists | 0:6b68dac0d986 | 25 | #define SPIFI_DBG 0 |
embeddedartists | 0:6b68dac0d986 | 26 | |
embeddedartists | 0:6b68dac0d986 | 27 | /* |
embeddedartists | 0:6b68dac0d986 | 28 | * The SPIFI_ROM_PTR (0x1FFF1FF8) points to an area where the pointers to |
embeddedartists | 0:6b68dac0d986 | 29 | * different drivers in ROM are stored. |
embeddedartists | 0:6b68dac0d986 | 30 | */ |
embeddedartists | 0:6b68dac0d986 | 31 | typedef struct { |
embeddedartists | 0:6b68dac0d986 | 32 | /*const*/ unsigned p_usbd; // USBROMD |
embeddedartists | 0:6b68dac0d986 | 33 | /*const*/ unsigned p_clib; |
embeddedartists | 0:6b68dac0d986 | 34 | /*const*/ unsigned p_cand; |
embeddedartists | 0:6b68dac0d986 | 35 | /*const*/ unsigned p_pwrd; // PWRROMD |
embeddedartists | 0:6b68dac0d986 | 36 | /*const*/ unsigned p_promd; // DIVROMD |
embeddedartists | 0:6b68dac0d986 | 37 | /*const*/ SPIFI_RTNS *pSPIFID; // SPIFIROMD |
embeddedartists | 0:6b68dac0d986 | 38 | /*const*/ unsigned p_dev3; |
embeddedartists | 0:6b68dac0d986 | 39 | /*const*/ unsigned p_dev4; |
embeddedartists | 0:6b68dac0d986 | 40 | } ROM; |
embeddedartists | 0:6b68dac0d986 | 41 | |
embeddedartists | 0:6b68dac0d986 | 42 | #define ROM_DRIVERS_PTR ((ROM *)(*((unsigned int *)SPIFI_ROM_PTR))) |
embeddedartists | 0:6b68dac0d986 | 43 | #define IS_ADDR_IN_SPIFI(__addr) ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE ) |
embeddedartists | 0:6b68dac0d986 | 44 | |
embeddedartists | 0:6b68dac0d986 | 45 | #define SPIFI_MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b)) |
embeddedartists | 0:6b68dac0d986 | 46 | |
embeddedartists | 0:6b68dac0d986 | 47 | /****************************************************************************** |
embeddedartists | 0:6b68dac0d986 | 48 | * Local variables |
embeddedartists | 0:6b68dac0d986 | 49 | *****************************************************************************/ |
embeddedartists | 0:6b68dac0d986 | 50 | |
embeddedartists | 0:6b68dac0d986 | 51 | /****************************************************************************** |
embeddedartists | 0:6b68dac0d986 | 52 | * Private Functions |
embeddedartists | 0:6b68dac0d986 | 53 | *****************************************************************************/ |
embeddedartists | 0:6b68dac0d986 | 54 | |
embeddedartists | 0:6b68dac0d986 | 55 | SPIFI::SpifiError SPIFI::translateError(int err, bool verify) |
embeddedartists | 0:6b68dac0d986 | 56 | { |
embeddedartists | 0:6b68dac0d986 | 57 | SpifiError res; |
embeddedartists | 0:6b68dac0d986 | 58 | |
embeddedartists | 0:6b68dac0d986 | 59 | _verError = 0; |
embeddedartists | 0:6b68dac0d986 | 60 | |
embeddedartists | 0:6b68dac0d986 | 61 | if (err == 0) |
embeddedartists | 0:6b68dac0d986 | 62 | { |
embeddedartists | 0:6b68dac0d986 | 63 | res = Ok; |
embeddedartists | 0:6b68dac0d986 | 64 | } |
embeddedartists | 0:6b68dac0d986 | 65 | else if ((err >= Uninitialized) && (err <= UnknownError)) |
embeddedartists | 0:6b68dac0d986 | 66 | { |
embeddedartists | 0:6b68dac0d986 | 67 | // This is a known error code |
embeddedartists | 0:6b68dac0d986 | 68 | res = (SpifiError)err; |
embeddedartists | 0:6b68dac0d986 | 69 | } |
embeddedartists | 0:6b68dac0d986 | 70 | else if ((err >= InternalError) && (err <= EraseConflict)) |
embeddedartists | 0:6b68dac0d986 | 71 | { |
embeddedartists | 0:6b68dac0d986 | 72 | // This is a known error code |
embeddedartists | 0:6b68dac0d986 | 73 | res = (SpifiError)err; |
embeddedartists | 0:6b68dac0d986 | 74 | } |
embeddedartists | 0:6b68dac0d986 | 75 | else if (verify) |
embeddedartists | 0:6b68dac0d986 | 76 | { |
embeddedartists | 0:6b68dac0d986 | 77 | // As verification was selected and err is not in the list of known |
embeddedartists | 0:6b68dac0d986 | 78 | // codes this falls into this category in the User's Manual: |
embeddedartists | 0:6b68dac0d986 | 79 | // |
embeddedartists | 0:6b68dac0d986 | 80 | // "Other non-zero values can occur if options selects verification. |
embeddedartists | 0:6b68dac0d986 | 81 | // They will be the address in the SPIFI memory area at which the |
embeddedartists | 0:6b68dac0d986 | 82 | // first discrepancy was found." |
embeddedartists | 0:6b68dac0d986 | 83 | _verError = err; |
embeddedartists | 0:6b68dac0d986 | 84 | res = Verification; |
embeddedartists | 0:6b68dac0d986 | 85 | } |
embeddedartists | 0:6b68dac0d986 | 86 | else |
embeddedartists | 0:6b68dac0d986 | 87 | { |
embeddedartists | 0:6b68dac0d986 | 88 | // Should never happen :-) as all listed error codes are covered but |
embeddedartists | 0:6b68dac0d986 | 89 | // to be on the safe side and not interpret this as a success, a generic |
embeddedartists | 0:6b68dac0d986 | 90 | // error is set. |
embeddedartists | 0:6b68dac0d986 | 91 | res = UnknownError; |
embeddedartists | 0:6b68dac0d986 | 92 | } |
embeddedartists | 0:6b68dac0d986 | 93 | return res; |
embeddedartists | 0:6b68dac0d986 | 94 | } |
embeddedartists | 0:6b68dac0d986 | 95 | |
embeddedartists | 0:6b68dac0d986 | 96 | /****************************************************************************** |
embeddedartists | 0:6b68dac0d986 | 97 | * Public Functions |
embeddedartists | 0:6b68dac0d986 | 98 | *****************************************************************************/ |
embeddedartists | 0:6b68dac0d986 | 99 | |
embeddedartists | 0:6b68dac0d986 | 100 | SPIFI::SPIFI() |
embeddedartists | 0:6b68dac0d986 | 101 | { |
embeddedartists | 0:6b68dac0d986 | 102 | _verError = 0; |
embeddedartists | 0:6b68dac0d986 | 103 | _initialized = false; |
embeddedartists | 0:6b68dac0d986 | 104 | _device = UnknownDevice; |
embeddedartists | 0:6b68dac0d986 | 105 | _memorySize = 0; |
embeddedartists | 0:6b68dac0d986 | 106 | _eraseBlockSize = 0; |
embeddedartists | 0:6b68dac0d986 | 107 | |
embeddedartists | 0:6b68dac0d986 | 108 | _romData = (SPIFIobj*)malloc(sizeof(SPIFIobj)); |
embeddedartists | 0:6b68dac0d986 | 109 | if (_romData == NULL) { |
embeddedartists | 0:6b68dac0d986 | 110 | debug("SPIFI: Failed to allocate memory for ROM data\n"); |
embeddedartists | 0:6b68dac0d986 | 111 | } |
embeddedartists | 0:6b68dac0d986 | 112 | } |
embeddedartists | 0:6b68dac0d986 | 113 | |
embeddedartists | 0:6b68dac0d986 | 114 | SPIFI::~SPIFI() |
embeddedartists | 0:6b68dac0d986 | 115 | { |
embeddedartists | 0:6b68dac0d986 | 116 | if (_romData != NULL) { |
embeddedartists | 0:6b68dac0d986 | 117 | free(_romData); |
embeddedartists | 0:6b68dac0d986 | 118 | } |
embeddedartists | 0:6b68dac0d986 | 119 | } |
embeddedartists | 0:6b68dac0d986 | 120 | |
embeddedartists | 0:6b68dac0d986 | 121 | SPIFI::SpifiError SPIFI::init() |
embeddedartists | 0:6b68dac0d986 | 122 | { |
embeddedartists | 0:6b68dac0d986 | 123 | if (!_initialized) { |
embeddedartists | 0:6b68dac0d986 | 124 | |
embeddedartists | 0:6b68dac0d986 | 125 | // Turn on SPIFI block as it is disabled on reset |
embeddedartists | 0:6b68dac0d986 | 126 | LPC_SC->PCONP |= 0x00010000; |
embeddedartists | 3:2fa7755f2cef | 127 | |
embeddedartists | 3:2fa7755f2cef | 128 | // Configure clock source as Main PLL and divider 2 to get 60MHz |
embeddedartists | 3:2fa7755f2cef | 129 | uint32_t spifi_clk_div = 2; |
embeddedartists | 3:2fa7755f2cef | 130 | LPC_SC->SPIFICLKSEL = (1<<8) | spifi_clk_div; |
embeddedartists | 0:6b68dac0d986 | 131 | |
embeddedartists | 0:6b68dac0d986 | 132 | // pinsel for SPIFI |
embeddedartists | 0:6b68dac0d986 | 133 | LPC_IOCON->P2_7 = 5; /* SPIFI_CSN @ P2.7 */ |
embeddedartists | 0:6b68dac0d986 | 134 | LPC_IOCON->P0_22 = 5; /* SPIFI_CLK @ P0.22 */ |
embeddedartists | 0:6b68dac0d986 | 135 | LPC_IOCON->P0_15 = 5; /* SPIFI_IO2 @ P0.15 */ |
embeddedartists | 0:6b68dac0d986 | 136 | LPC_IOCON->P0_16 = 5; /* SPIFI_IO3 @ P0.16 */ |
embeddedartists | 0:6b68dac0d986 | 137 | LPC_IOCON->P0_17 = 5; /* SPIFI_IO1 @ P0.17 */ |
embeddedartists | 0:6b68dac0d986 | 138 | LPC_IOCON->P0_18 = 5; /* SPIFI_IO0 @ P0.18 */ |
embeddedartists | 0:6b68dac0d986 | 139 | |
embeddedartists | 0:6b68dac0d986 | 140 | uint32_t spifi_clk_mhz = (SystemCoreClock / spifi_clk_div) / 1000000; |
embeddedartists | 0:6b68dac0d986 | 141 | |
embeddedartists | 0:6b68dac0d986 | 142 | _spifi = ROM_DRIVERS_PTR->pSPIFID; |
embeddedartists | 0:6b68dac0d986 | 143 | |
embeddedartists | 0:6b68dac0d986 | 144 | /* Typical time tCS is 20 ns min, we give 200 ns to be on safer side */ |
embeddedartists | 0:6b68dac0d986 | 145 | int rc = _spifi->spifi_init (_romData, spifi_clk_mhz/5, S_FULLCLK+S_RCVCLK, spifi_clk_mhz); |
embeddedartists | 0:6b68dac0d986 | 146 | if (rc) { |
embeddedartists | 0:6b68dac0d986 | 147 | _spifi = NULL; |
embeddedartists | 0:6b68dac0d986 | 148 | return translateError(rc); |
embeddedartists | 0:6b68dac0d986 | 149 | } |
embeddedartists | 0:6b68dac0d986 | 150 | |
embeddedartists | 0:6b68dac0d986 | 151 | /* Make sure it is a tested flash module */ |
embeddedartists | 0:6b68dac0d986 | 152 | if ((_romData->mfger == 1) && (_romData->devType == 0x2) && (_romData->devID == 0x15) && (_romData->memSize > 0x100000)) |
embeddedartists | 0:6b68dac0d986 | 153 | { |
embeddedartists | 0:6b68dac0d986 | 154 | _device = Spansion_S25FL032; |
embeddedartists | 0:6b68dac0d986 | 155 | _memorySize = _romData->memSize; |
embeddedartists | 0:6b68dac0d986 | 156 | _eraseBlockSize = 64*1024; |
embeddedartists | 0:6b68dac0d986 | 157 | } |
embeddedartists | 0:6b68dac0d986 | 158 | else if ((_romData->mfger == 0xef) && (_romData->devType == 0x40) && (_romData->devID == 0x17) && (_romData->memSize > 0x100000)) |
embeddedartists | 0:6b68dac0d986 | 159 | { |
embeddedartists | 0:6b68dac0d986 | 160 | _device = Winbond_W25Q64FV; |
embeddedartists | 0:6b68dac0d986 | 161 | _memorySize = _romData->memSize; |
embeddedartists | 0:6b68dac0d986 | 162 | _eraseBlockSize = 4*1024; |
embeddedartists | 0:6b68dac0d986 | 163 | } |
embeddedartists | 0:6b68dac0d986 | 164 | else if ((_romData->mfger == 0xc2) && (_romData->devType == 0x20) && (_romData->devID == 0x17) && (_romData->memSize > 0x100000)) |
embeddedartists | 0:6b68dac0d986 | 165 | { |
embeddedartists | 0:6b68dac0d986 | 166 | _device = Macronix_MX25L6435EM2I; |
embeddedartists | 0:6b68dac0d986 | 167 | _memorySize = _romData->memSize; |
embeddedartists | 0:6b68dac0d986 | 168 | _eraseBlockSize = 4*1024; |
embeddedartists | 0:6b68dac0d986 | 169 | } |
embeddedartists | 0:6b68dac0d986 | 170 | else |
embeddedartists | 0:6b68dac0d986 | 171 | { |
embeddedartists | 0:6b68dac0d986 | 172 | debug("SPIFI::init(): Memory is unknown and may not work as expected\n"); |
embeddedartists | 0:6b68dac0d986 | 173 | |
embeddedartists | 0:6b68dac0d986 | 174 | // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032 |
embeddedartists | 0:6b68dac0d986 | 175 | _device = UnknownDevice; |
embeddedartists | 0:6b68dac0d986 | 176 | _memorySize = _romData->memSize; |
embeddedartists | 0:6b68dac0d986 | 177 | _eraseBlockSize = 64*1024; |
embeddedartists | 0:6b68dac0d986 | 178 | |
embeddedartists | 0:6b68dac0d986 | 179 | /* |
embeddedartists | 0:6b68dac0d986 | 180 | * If this happens, check the manufacturer and device information |
embeddedartists | 0:6b68dac0d986 | 181 | * and compare with the data sheet for your chip. Also make sure |
embeddedartists | 0:6b68dac0d986 | 182 | * that the sector sizes are the same (i.e. 64KB) for your chip. |
embeddedartists | 0:6b68dac0d986 | 183 | * If everything is the same then add an exception for your chip. |
embeddedartists | 0:6b68dac0d986 | 184 | */ |
embeddedartists | 0:6b68dac0d986 | 185 | } |
embeddedartists | 0:6b68dac0d986 | 186 | |
embeddedartists | 0:6b68dac0d986 | 187 | _initialized = true; |
embeddedartists | 0:6b68dac0d986 | 188 | } |
embeddedartists | 0:6b68dac0d986 | 189 | return Ok; |
embeddedartists | 0:6b68dac0d986 | 190 | } |
embeddedartists | 0:6b68dac0d986 | 191 | |
embeddedartists | 0:6b68dac0d986 | 192 | SPIFI::SpifiError SPIFI::program(uint32_t dest, unsigned len, char* src, Options options, bool verify, char* scratch) |
embeddedartists | 0:6b68dac0d986 | 193 | { |
embeddedartists | 0:6b68dac0d986 | 194 | unsigned written = 0; |
embeddedartists | 0:6b68dac0d986 | 195 | SPIFIopers opers; |
embeddedartists | 0:6b68dac0d986 | 196 | opers.dest = (char *)dest; |
embeddedartists | 0:6b68dac0d986 | 197 | opers.length = SPIFI_MIN(len, PROG_SIZE); |
embeddedartists | 0:6b68dac0d986 | 198 | opers.scratch = scratch; |
embeddedartists | 0:6b68dac0d986 | 199 | opers.protect = 0; |
embeddedartists | 0:6b68dac0d986 | 200 | opers.options = options; |
embeddedartists | 0:6b68dac0d986 | 201 | if (verify) { |
embeddedartists | 0:6b68dac0d986 | 202 | opers.options |= S_VERIFY_PROG; |
embeddedartists | 0:6b68dac0d986 | 203 | } |
embeddedartists | 0:6b68dac0d986 | 204 | |
embeddedartists | 0:6b68dac0d986 | 205 | if (IS_ADDR_IN_SPIFI(src)) |
embeddedartists | 0:6b68dac0d986 | 206 | { |
embeddedartists | 0:6b68dac0d986 | 207 | // The SPIFI ROM driver cannot write data from SPIFI into |
embeddedartists | 0:6b68dac0d986 | 208 | // SPIFI (i.e. cannot read and write at the same time). |
embeddedartists | 0:6b68dac0d986 | 209 | // The workaround is to copy the source data into a buffer |
embeddedartists | 0:6b68dac0d986 | 210 | // in local memory and use that as source for the write |
embeddedartists | 0:6b68dac0d986 | 211 | // instead. |
embeddedartists | 0:6b68dac0d986 | 212 | while (written < len) { |
embeddedartists | 0:6b68dac0d986 | 213 | memcpy(_addrConflictBuff, src + written, opers.length); |
embeddedartists | 0:6b68dac0d986 | 214 | int rc = _spifi->spifi_program(_romData, _addrConflictBuff, &opers); |
embeddedartists | 0:6b68dac0d986 | 215 | if (rc) |
embeddedartists | 0:6b68dac0d986 | 216 | { |
embeddedartists | 0:6b68dac0d986 | 217 | // got an error |
embeddedartists | 0:6b68dac0d986 | 218 | return translateError(rc, verify); |
embeddedartists | 0:6b68dac0d986 | 219 | } |
embeddedartists | 0:6b68dac0d986 | 220 | written += opers.length; |
embeddedartists | 0:6b68dac0d986 | 221 | opers.dest += opers.length; |
embeddedartists | 0:6b68dac0d986 | 222 | opers.length = SPIFI_MIN(len - written, PROG_SIZE); |
embeddedartists | 0:6b68dac0d986 | 223 | } |
embeddedartists | 0:6b68dac0d986 | 224 | } |
embeddedartists | 0:6b68dac0d986 | 225 | else |
embeddedartists | 0:6b68dac0d986 | 226 | { |
embeddedartists | 0:6b68dac0d986 | 227 | while (written < len) { |
embeddedartists | 0:6b68dac0d986 | 228 | int rc = _spifi->spifi_program(_romData, src + written, &opers); |
embeddedartists | 0:6b68dac0d986 | 229 | if (rc) |
embeddedartists | 0:6b68dac0d986 | 230 | { |
embeddedartists | 0:6b68dac0d986 | 231 | // got an error |
embeddedartists | 0:6b68dac0d986 | 232 | return translateError(rc, verify); |
embeddedartists | 0:6b68dac0d986 | 233 | } |
embeddedartists | 0:6b68dac0d986 | 234 | written += opers.length; |
embeddedartists | 0:6b68dac0d986 | 235 | opers.dest += opers.length; |
embeddedartists | 0:6b68dac0d986 | 236 | opers.length = SPIFI_MIN(len - written, PROG_SIZE); |
embeddedartists | 0:6b68dac0d986 | 237 | } |
embeddedartists | 0:6b68dac0d986 | 238 | } |
embeddedartists | 0:6b68dac0d986 | 239 | |
embeddedartists | 0:6b68dac0d986 | 240 | return Ok; |
embeddedartists | 0:6b68dac0d986 | 241 | } |
embeddedartists | 0:6b68dac0d986 | 242 | |
embeddedartists | 0:6b68dac0d986 | 243 | SPIFI::SpifiError SPIFI::erase(uint32_t dest, unsigned len, char* src, bool verify, char* scratch) |
embeddedartists | 0:6b68dac0d986 | 244 | { |
embeddedartists | 0:6b68dac0d986 | 245 | SPIFIopers opers; |
embeddedartists | 0:6b68dac0d986 | 246 | opers.dest = (char *)dest; |
embeddedartists | 0:6b68dac0d986 | 247 | opers.length = len; |
embeddedartists | 0:6b68dac0d986 | 248 | opers.scratch = scratch; |
embeddedartists | 0:6b68dac0d986 | 249 | opers.protect = 0; |
embeddedartists | 0:6b68dac0d986 | 250 | if (verify) { |
embeddedartists | 0:6b68dac0d986 | 251 | opers.options = S_VERIFY_ERASE; |
embeddedartists | 0:6b68dac0d986 | 252 | } else { |
embeddedartists | 0:6b68dac0d986 | 253 | opers.options = S_NO_VERIFY; |
embeddedartists | 0:6b68dac0d986 | 254 | } |
embeddedartists | 0:6b68dac0d986 | 255 | int rc = _spifi->spifi_erase(_romData, &opers); |
embeddedartists | 0:6b68dac0d986 | 256 | return translateError(rc); |
embeddedartists | 0:6b68dac0d986 | 257 | } |
embeddedartists | 0:6b68dac0d986 | 258 | |
embeddedartists | 0:6b68dac0d986 | 259 |