1 /******************************************************************************
3 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the
17 * Neither the name of Texas Instruments Incorporated nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ******************************************************************************/
37 #include "driverlib.h"
39 #include "MSP432E4_FlashLibIf.h"
41 /* Local prototypes */
42 void msp432_flash_init(void);
43 void msp432_flash_mass_erase(void);
44 void msp432_flash_sector_erase(void);
45 void msp432_flash_write(void);
46 void msp432_flash_continous_write(void);
47 void msp432_flash_exit(void);
51 /* Disable interrupts */
55 SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0);
58 switch (FLASH_LOADER->FLASH_FUNCTION) {
60 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
62 FLASH_LOADER->FLASH_FUNCTION = 0;
64 case FLASH_MASS_ERASE:
65 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
66 msp432_flash_mass_erase();
67 FLASH_LOADER->FLASH_FUNCTION = 0;
69 case FLASH_SECTOR_ERASE:
70 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
71 msp432_flash_sector_erase();
72 FLASH_LOADER->FLASH_FUNCTION = 0;
75 case FLASH_CONTINUOUS_PROGRAM:
76 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
77 msp432_flash_continous_write();
78 FLASH_LOADER->FLASH_FUNCTION = 0;
81 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
83 FLASH_LOADER->FLASH_FUNCTION = 0;
85 case FLASH_NO_COMMAND:
88 FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND;
94 /* Initialize flash */
95 void msp432_flash_init(void)
97 SCB->VTOR = 0x20000000;
98 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
101 /* Erase entire flash */
102 void msp432_flash_mass_erase(void)
104 bool success = false;
106 /* Clear the flash access and error interrupts. */
107 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
108 FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
110 /* Trigger mass erase */
111 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE;
112 while (FLASH_CTRL->FMC & FLASH_FMC_MERASE)
115 /* Return an error if an access violation occurred. */
116 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
119 FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR;
121 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
124 /* Erase one flash sector */
125 void msp432_flash_sector_erase(void)
127 bool success = false;
129 /* Clear the flash access and error interrupts. */
130 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
131 FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
133 /* Set 16kB aligned flash page address to be erased (16kB block) */
134 FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS;
135 /* Trigger sector erase (erase flash page) */
136 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
137 while (FLASH_CTRL->FMC & FLASH_FMC_ERASE)
140 /* Return an error if an access violation occurred. */
141 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
145 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
147 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
150 /* Write data to flash */
151 void msp432_flash_continous_write(void)
153 bool buffer1_in_use = false;
154 bool buffer2_in_use = false;
155 uint32_t *src_address = NULL;
158 uint32_t address = FLASH_LOADER->DST_ADDRESS;
159 uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH;
160 int32_t write_package = 0;
162 /* Clear the flash access and error interrupts. */
163 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
164 FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC);
166 if (data_to_write > SRC_LENGTH_MAX) {
167 write_package = SRC_LENGTH_MAX;
168 data_to_write -= write_package;
170 write_package = data_to_write;
171 data_to_write -= write_package;
173 while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) &&
174 !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY))
177 if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) {
178 FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE;
179 src_address = (uint32_t *) RAM_LOADER_BUFFER1;
180 buffer1_in_use = true;
181 } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) {
182 FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE;
183 src_address = (uint32_t *) RAM_LOADER_BUFFER2;
184 buffer2_in_use = true;
188 * The flash hardware can only write complete words to flash. If
189 * an unaligned address is passed in, we must do a read-modify-write
190 * on a word with enough bytes to align the rest of the buffer. And
191 * if less than a whole word remains at the end, we must also do a
192 * read-modify-write on a final word to finish up.
194 if (0 != (address & 0x3)) {
196 uint8_t *ui8head = (uint8_t *)&head;
197 uint8_t *buffer = (uint8_t *)src_address;
199 /* Get starting offset for data to write (will be 1 to 3) */
200 uint32_t head_offset = address & 0x03;
202 /* Get the aligned address to write this first word to */
203 uint32_t head_address = address & 0xfffffffc;
205 /* Retrieve what is already in flash at the head address */
206 head = *(uint32_t *)head_address;
208 /* Substitute in the new data to write */
209 while ((write_package > 0) && (head_offset < 4)) {
210 ui8head[head_offset] = *buffer;
216 src_address = (uint32_t *)buffer;
218 FLASH_CTRL->FMD = head;
219 FLASH_CTRL->FMA = head_address;
220 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
222 /* Wait until the word has been programmed. */
223 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
226 /* Return an error if an access violation occurred. */
227 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
228 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
231 /* Program a word at a time until aligned on 32-word boundary */
232 while ((write_package >= 4) && ((address & 0x7f) != 0) && success) {
233 FLASH_CTRL->FMD = *src_address++;
234 FLASH_CTRL->FMA = address;
235 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
237 /* Wait until the word has been programmed. */
238 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
241 /* Prepare for next word to write */
245 /* Return an error if an access violation occurred. */
246 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
247 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
250 /* Program data in 32-word blocks */
251 while ((write_package >= 32) && success) {
252 /* Loop over the words in this 32-word block. */
255 FLASH_CTRL->FWBN[i] = *src_address++;
258 } while ((write_package > 0) && (i < 32));
259 FLASH_CTRL->FMA = address;
260 FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF;
262 /* Wait until the write buffer has been programmed. */
263 while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF)
266 /* Increment destination address by words written */
269 /* Return an error if an access violation occurred. */
270 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
271 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
274 /* Program a word at a time on left over data */
275 while ((write_package >= 4) && success) {
276 FLASH_CTRL->FMD = *src_address++;
277 FLASH_CTRL->FMA = address;
278 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
280 /* Wait until the word has been programmed. */
281 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
284 /* Prepare for next word to write */
288 /* Return an error if an access violation occurred. */
289 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
290 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
293 if ((write_package > 0) && success) {
295 uint8_t *ui8tail = (uint8_t *)&tail;
296 uint8_t *buffer = (uint8_t *)src_address;
298 /* Set starting offset for data to write */
299 uint32_t tail_offset = 0;
301 /* Get the address to write this last word to */
302 uint32_t tail_address = address;
304 /* Retrieve what is already in flash at the tail address */
305 tail = *(uint32_t *)address;
307 /* Substitute in the new data to write */
308 while (write_package > 0) {
309 ui8tail[tail_offset] = *buffer;
316 FLASH_CTRL->FMD = tail;
317 FLASH_CTRL->FMA = tail_address;
318 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
320 /* Wait until the word has been programmed. */
321 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
324 /* Return an error if an access violation occurred. */
325 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
326 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
329 if (buffer1_in_use) {
330 FLASH_LOADER->BUFFER1_STATUS_REGISTER &=
331 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
332 buffer1_in_use = false;
333 } else if (buffer2_in_use) {
334 FLASH_LOADER->BUFFER2_STATUS_REGISTER &=
335 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
336 buffer2_in_use = false;
338 } while (success && data_to_write);
341 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
343 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
346 /* Exit flash programming */
347 void msp432_flash_exit(void)
349 SCB->VTOR = 0x00000000;
350 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;