forked from ARMmbed/mbed-os
/
flash_api.c
218 lines (178 loc) · 5.81 KB
/
flash_api.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if DEVICE_FLASH
#include "mbed_critical.h"
#include "flash_api.h"
#include "mbed_assert.h"
#include "cmsis.h"
#include <stdlib.h>
#include <string.h>
#define MEMMAP (*((volatile unsigned long *) 0x400FC040))
#define PLL0CON (*((volatile unsigned long *) 0x400FC080))
#define PLL0CFG (*((volatile unsigned long *) 0x400FC084))
#define PLL0STAT (*((volatile unsigned long *) 0x400FC088))
#define PLL0FEED (*((volatile unsigned long *) 0x400FC08C))
#define CCLKSEL (*((volatile unsigned long *) 0x400FC104))
#define CLKSRCSEL (*((volatile unsigned long *) 0x400FC10C))
#define STACK_SIZE 64 // Stack Size
#define SET_VALID_CODE 1 // Set Valid User Code Signature
/* IAP Call */
typedef void (*IAP_Entry) (unsigned long *cmd, unsigned long *stat);
#define IAP_Call ((IAP_Entry) 0x1FFF1FF1)
typedef struct flash_s flash_t;
unsigned long CCLK; // CCLK in kHz
struct sIAP { // IAP Structure
unsigned long cmd;// Command
unsigned long par[4];// Parameters
unsigned long stat;// Status
unsigned long res[2];// Result
}IAP;
/*
* Get Sector Number
* Parameter: address: Sector Address
* Return Value: Sector Number
*/
unsigned long GetSecNum (unsigned long address)
{
unsigned long n;
n = address >> 12; // 4kB Sector
if (n >= 0x10) {
n = 0x0E + (n >> 3); // 32kB Sector
}
return (n); // Sector Number
}
int32_t flash_init(flash_t *obj)
{
CCLK = SystemCoreClock / 1000; // CCLK value is in kHz, clk in Hz
MEMMAP = 0x01;// User Flash Mode
return (0);
}
int32_t flash_free(flash_t *obj)
{
return 0;
}
int32_t flash_erase_sector(flash_t *obj, uint32_t address)
{
unsigned long n;
n = GetSecNum(address); // Get Sector Number
core_util_critical_section_enter();
IAP.cmd = 50;// Prepare Sector for Erase
IAP.par[0] = n;// Start Sector
IAP.par[1] = n;// End Sector
IAP_Call (&IAP.cmd, &IAP.stat);// Call IAP Command
if (IAP.stat) {
return (1); // Command Failed
}
IAP.cmd = 52; // Erase Sector
IAP.par[0] = n;// Start Sector
IAP.par[1] = n;// End Sector
IAP.par[2] = CCLK;// CCLK in kHz
IAP_Call (&IAP.cmd, &IAP.stat);// Call IAP Command
core_util_critical_section_exit();
if (IAP.stat) {
return (1); // Command Failed
}
return (0); // Finished without Errors
}
int32_t flash_program_page(flash_t *obj, uint32_t address,
const uint8_t *data, uint32_t size)
{
unsigned long n;
const uint32_t pageSize = flash_get_page_size(obj);
uint8_t *tempBuffer, *source;
tempBuffer = 0;
source = (uint8_t *)data;
// On LPC1768, the first RAM bank starts at 0x1000000, so anywhere below that has to be flash.
// The IAP firmware does not support flash to flash copies, so if the source data is in flash
// it must be buffered in RAM.
bool isFlashToFlashCopy = (ptrdiff_t)(data) < 0x10000000;
// check word boundary
if (isFlashToFlashCopy) {
// always malloc outside critical section
tempBuffer = malloc(pageSize);
if (tempBuffer == 0) {
return -1;
}
}
n = GetSecNum(address); // Get Sector Number
core_util_critical_section_enter();
for(size_t pageIdx = 0; pageIdx < (size / pageSize); ++pageIdx)
{
uint8_t * pageSourceAddr = source + (pageIdx * pageSize);
if (isFlashToFlashCopy) {
memcpy(tempBuffer, pageSourceAddr, pageSize);
pageSourceAddr = tempBuffer;
}
/*
Prepare_Sector_for_Write command must be exected before
Copy_RAM_to_Flash command.
*/
IAP.cmd = 50; // Prepare Sector for Write
IAP.par[0] = n; // Start Sector
IAP.par[1] = n; // End Sector
IAP_Call (&IAP.cmd, &IAP.stat); // Call IAP Command
if (IAP.stat) {
core_util_critical_section_exit();
return -1; // Command Failed
}
IAP.cmd = 51; // Copy RAM to Flash
IAP.par[0] = address; // Destination Flash Address
IAP.par[1] = (unsigned long)pageSourceAddr; // Source RAM Address
IAP.par[2] = pageSize; // number of bytes to be written
IAP.par[3] = CCLK; // CCLK in kHz
IAP_Call (&IAP.cmd, &IAP.stat); // Call IAP Command
if (IAP.stat) {
core_util_critical_section_exit();
return -1; // Command Failed
}
address += pageSize;
}
core_util_critical_section_exit();
if(tempBuffer != 0) { // We allocated our own memory
free(tempBuffer);
}
return (0); // Finished without Errors
}
uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address)
{
if (address < flash_get_start_address(obj) || address >= flash_get_start_address(obj) +flash_get_size(obj)) {
return MBED_FLASH_INVALID_SIZE;
}
if(GetSecNum(address)>=0x10) {
return 0x8000;
} else {
return 0x1000;
}
}
uint32_t flash_get_page_size(const flash_t *obj)
{
return 1024;
}
uint32_t flash_get_start_address(const flash_t *obj)
{
return LPC_FLASH_BASE;
}
uint32_t flash_get_size(const flash_t *obj)
{
return 0x80000;
}
uint8_t flash_get_erase_value(const flash_t *obj)
{
(void)obj;
return 0xFF;
}
#endif