1 /* SPDX-License-Identifier: BSD-3-Clause */
3 /******************************************************************************
5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
7 ******************************************************************************/
11 #include "driverlib.h"
13 #include "MSP432E4_FlashLibIf.h"
15 /* Local prototypes */
16 void msp432_flash_init(void);
17 void msp432_flash_mass_erase(void);
18 void msp432_flash_sector_erase(void);
19 void msp432_flash_write(void);
20 void msp432_flash_continous_write(void);
21 void msp432_flash_exit(void);
25 /* Disable interrupts */
29 SYSCTL->RCGCWD &= ~(SYSCTL_RCGCWD_R1 + SYSCTL_RCGCWD_R0);
32 switch (FLASH_LOADER->FLASH_FUNCTION) {
34 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
36 FLASH_LOADER->FLASH_FUNCTION = 0;
38 case FLASH_MASS_ERASE:
39 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
40 msp432_flash_mass_erase();
41 FLASH_LOADER->FLASH_FUNCTION = 0;
43 case FLASH_SECTOR_ERASE:
44 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
45 msp432_flash_sector_erase();
46 FLASH_LOADER->FLASH_FUNCTION = 0;
49 case FLASH_CONTINUOUS_PROGRAM:
50 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
51 msp432_flash_continous_write();
52 FLASH_LOADER->FLASH_FUNCTION = 0;
55 FLASH_LOADER->RETURN_CODE = FLASH_BUSY;
57 FLASH_LOADER->FLASH_FUNCTION = 0;
59 case FLASH_NO_COMMAND:
62 FLASH_LOADER->RETURN_CODE = FLASH_WRONG_COMMAND;
68 /* Initialize flash */
69 void msp432_flash_init(void)
71 SCB->VTOR = 0x20000000;
72 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
75 /* Erase entire flash */
76 void msp432_flash_mass_erase(void)
80 /* Clear the flash access and error interrupts. */
81 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
82 FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
84 /* Trigger mass erase */
85 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_MERASE;
86 while (FLASH_CTRL->FMC & FLASH_FMC_MERASE)
89 /* Return an error if an access violation occurred. */
90 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
93 FLASH_LOADER->RETURN_CODE = FLASH_VERIFY_ERROR;
95 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
98 /* Erase one flash sector */
99 void msp432_flash_sector_erase(void)
101 bool success = false;
103 /* Clear the flash access and error interrupts. */
104 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
105 FLASH_FCMISC_ERMISC | FLASH_FCMISC_PMISC);
107 /* Set 16kB aligned flash page address to be erased (16kB block) */
108 FLASH_CTRL->FMA = FLASH_LOADER->DST_ADDRESS;
109 /* Trigger sector erase (erase flash page) */
110 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_ERASE;
111 while (FLASH_CTRL->FMC & FLASH_FMC_ERASE)
114 /* Return an error if an access violation occurred. */
115 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS | FLASH_FCRIS_VOLTRIS |
119 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
121 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
124 /* Write data to flash */
125 void msp432_flash_continous_write(void)
127 bool buffer1_in_use = false;
128 bool buffer2_in_use = false;
129 uint32_t *src_address = NULL;
132 uint32_t address = FLASH_LOADER->DST_ADDRESS;
133 uint32_t data_to_write = FLASH_LOADER->SRC_LENGTH;
134 int32_t write_package = 0;
136 /* Clear the flash access and error interrupts. */
137 FLASH_CTRL->FCMISC = (FLASH_FCMISC_AMISC | FLASH_FCMISC_VOLTMISC |
138 FLASH_FCMISC_INVDMISC | FLASH_FCMISC_PROGMISC | FLASH_FCMISC_PMISC);
140 if (data_to_write > SRC_LENGTH_MAX) {
141 write_package = SRC_LENGTH_MAX;
142 data_to_write -= write_package;
144 write_package = data_to_write;
145 data_to_write -= write_package;
147 while (!(FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) &&
148 !(FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY))
151 if (FLASH_LOADER->BUFFER1_STATUS_REGISTER & BUFFER_DATA_READY) {
152 FLASH_LOADER->BUFFER1_STATUS_REGISTER |= BUFFER_ACTIVE;
153 src_address = (uint32_t *) RAM_LOADER_BUFFER1;
154 buffer1_in_use = true;
155 } else if (FLASH_LOADER->BUFFER2_STATUS_REGISTER & BUFFER_DATA_READY) {
156 FLASH_LOADER->BUFFER2_STATUS_REGISTER |= BUFFER_ACTIVE;
157 src_address = (uint32_t *) RAM_LOADER_BUFFER2;
158 buffer2_in_use = true;
162 * The flash hardware can only write complete words to flash. If
163 * an unaligned address is passed in, we must do a read-modify-write
164 * on a word with enough bytes to align the rest of the buffer. And
165 * if less than a whole word remains at the end, we must also do a
166 * read-modify-write on a final word to finish up.
168 if (0 != (address & 0x3)) {
170 uint8_t *ui8head = (uint8_t *)&head;
171 uint8_t *buffer = (uint8_t *)src_address;
173 /* Get starting offset for data to write (will be 1 to 3) */
174 uint32_t head_offset = address & 0x03;
176 /* Get the aligned address to write this first word to */
177 uint32_t head_address = address & 0xfffffffc;
179 /* Retrieve what is already in flash at the head address */
180 head = *(uint32_t *)head_address;
182 /* Substitute in the new data to write */
183 while ((write_package > 0) && (head_offset < 4)) {
184 ui8head[head_offset] = *buffer;
190 src_address = (uint32_t *)buffer;
192 FLASH_CTRL->FMD = head;
193 FLASH_CTRL->FMA = head_address;
194 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
196 /* Wait until the word has been programmed. */
197 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
200 /* Return an error if an access violation occurred. */
201 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
202 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
205 /* Program a word at a time until aligned on 32-word boundary */
206 while ((write_package >= 4) && ((address & 0x7f) != 0) && success) {
207 FLASH_CTRL->FMD = *src_address++;
208 FLASH_CTRL->FMA = address;
209 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
211 /* Wait until the word has been programmed. */
212 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
215 /* Prepare for next word to write */
219 /* Return an error if an access violation occurred. */
220 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
221 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
224 /* Program data in 32-word blocks */
225 while ((write_package >= 32) && success) {
226 /* Loop over the words in this 32-word block. */
229 FLASH_CTRL->FWBN[i] = *src_address++;
232 } while ((write_package > 0) && (i < 32));
233 FLASH_CTRL->FMA = address;
234 FLASH_CTRL->FMC2 = FLASH_FMC_WRKEY | FLASH_FMC2_WRBUF;
236 /* Wait until the write buffer has been programmed. */
237 while (FLASH_CTRL->FMC2 & FLASH_FMC2_WRBUF)
240 /* Increment destination address by words written */
243 /* Return an error if an access violation occurred. */
244 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
245 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
248 /* Program a word at a time on left over data */
249 while ((write_package >= 4) && success) {
250 FLASH_CTRL->FMD = *src_address++;
251 FLASH_CTRL->FMA = address;
252 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
254 /* Wait until the word has been programmed. */
255 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
258 /* Prepare for next word to write */
262 /* Return an error if an access violation occurred. */
263 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
264 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
267 if ((write_package > 0) && success) {
269 uint8_t *ui8tail = (uint8_t *)&tail;
270 uint8_t *buffer = (uint8_t *)src_address;
272 /* Set starting offset for data to write */
273 uint32_t tail_offset = 0;
275 /* Get the address to write this last word to */
276 uint32_t tail_address = address;
278 /* Retrieve what is already in flash at the tail address */
279 tail = *(uint32_t *)address;
281 /* Substitute in the new data to write */
282 while (write_package > 0) {
283 ui8tail[tail_offset] = *buffer;
290 FLASH_CTRL->FMD = tail;
291 FLASH_CTRL->FMA = tail_address;
292 FLASH_CTRL->FMC = FLASH_FMC_WRKEY | FLASH_FMC_WRITE;
294 /* Wait until the word has been programmed. */
295 while (FLASH_CTRL->FMC & FLASH_FMC_WRITE)
298 /* Return an error if an access violation occurred. */
299 success = !(FLASH_CTRL->FCRIS & (FLASH_FCRIS_ARIS |
300 FLASH_FCRIS_ERIS | FLASH_FCRIS_INVDRIS | FLASH_FCRIS_PROGRIS));
303 if (buffer1_in_use) {
304 FLASH_LOADER->BUFFER1_STATUS_REGISTER &=
305 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
306 buffer1_in_use = false;
307 } else if (buffer2_in_use) {
308 FLASH_LOADER->BUFFER2_STATUS_REGISTER &=
309 ~(BUFFER_ACTIVE | BUFFER_DATA_READY);
310 buffer2_in_use = false;
312 } while (success && data_to_write);
315 FLASH_LOADER->RETURN_CODE = FLASH_ERROR;
317 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;
320 /* Exit flash programming */
321 void msp432_flash_exit(void)
323 SCB->VTOR = 0x00000000;
324 FLASH_LOADER->RETURN_CODE = FLASH_SUCCESS;