1 | /*
|
2 | Andreas Weschenfelder
|
3 |
|
4 | 22.07.07
|
5 |
|
6 | IAP-Functions
|
7 | */
|
8 |
|
9 | #include <stdio.h>
|
10 |
|
11 | /*
|
12 | * Choose sector and address
|
13 | *
|
14 | * The sector address depends on the processor type.
|
15 | * The LPC213x uses 4KB for the first 8 sectors, all
|
16 | * others use 8KB. If sector is <8, then the address
|
17 | * is sector*0x2000 (sector*0x1000 for the LPC213x).
|
18 | */
|
19 | #define SECT 7
|
20 | #ifdef lc2138 //-> =2148? -> nachschauen
|
21 | #define ADDR 0x7000
|
22 | #else
|
23 | #ifdef lc2148
|
24 | #define ADDR 0x7000
|
25 | #else
|
26 | #define ADDR 0xe000
|
27 | #endif
|
28 | #endif
|
29 |
|
30 | //#define _XTAL 12000000
|
31 | //in khz?!?
|
32 | #define _XTAL 12000
|
33 |
|
34 |
|
35 |
|
36 | //IAP-Commands
|
37 | #define PREPARE_SECTOR_FOR_WRITE_OPERATION 50
|
38 | #define COPY_RAM_TO_FLASH 51
|
39 | #define ERASE_SECTOR 52
|
40 | #define BLANK_CHECK_SECTOR 53
|
41 | #define READ_PART_ID 54
|
42 | #define READ_BOOT_CODE_VERSION 55
|
43 | #define COMPARE 56
|
44 |
|
45 | //ISP_READ_MEMORY_CMD
|
46 | //ISP_Go <address> <mode>
|
47 |
|
48 |
|
49 | //PartIDs
|
50 | #define PART_ID_LPC2141 0x0402FF01
|
51 | #define PART_ID_LPC2142 0x0402FF11
|
52 | #define PART_ID_LPC2144 0x0402FF12
|
53 | #define PART_ID_LPC2146 0x0402FF23
|
54 | #define PART_ID_LPC2148 0x0402FF25
|
55 |
|
56 |
|
57 | //IAP-Status-Codes
|
58 |
|
59 | #define CMD_SUCCESS 0 //Command is executed successfully.
|
60 | #define INVALID_COMMAND 1 //Invalid command.
|
61 | #define SRC_ADDR_ERROR 2 //Source address is not on a word boundary.
|
62 | #define DST_ADDR_ERROR 3 //Destination address is not on a correct boundary.
|
63 | #define SRC_ADDR_NOT_MAPPED 4 //Source address is not mapped in the memory map. Count value is taken in to consideration where applicable.
|
64 | #define DST_ADDR_NOT_MAPPED 5 //Destination address is not mapped in the memory map. Count value is taken in to consideration where applicable.
|
65 | #define COUNT_ERROR 6 //Byte count is not multiple of 4 or is not a permitted value.
|
66 | #define INVALID_SECTOR 7 //Sector number is invalid
|
67 | #define SECTOR_NOT_BLANK 8 //Sector is not blank.
|
68 | #define SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9 //Command to prepare sector for write operation was not executed.
|
69 | #define COMPARE_ERROR 10 //Source and destination data is not same.
|
70 | #define BUSY 11 //Flash programming hardware interface is busy
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 | static unsigned long iap_cmd[5]; // IAP command table
|
77 | static unsigned long iap_res[3]; // result table
|
78 |
|
79 | static long iap(long code, long p1, long p2, long p3, long p4);
|
80 | static void part_id(void);
|
81 | static void s_write(void);
|
82 | static void s_erase(void);
|
83 |
|
84 | long blank_check_sector(long tmp_sect1, long tmp_sect2);
|
85 | long compare(long tmp_adr_dst,long tmp_adr_src, long tmp_size);
|
86 | long erase(long tmp_sect1, long tmp_sect2 );
|
87 | long copy_ram_to_flash( long tmp_adr_dst,long tmp_adr_src, long tmp_size );
|
88 | long prepare_sector( long tmp_sect1, long tmp_sect2 );
|
89 | long read_boot_code_version(void);
|
90 |
|
91 | void _pll_off(void);
|
92 | void _pll_on(void) ;
|
93 |
|
94 | /*
|
95 | * Call IAP function.
|
96 | *
|
97 | * Note: Direct XTAL mode is required
|
98 | * for IAP functions (PLL turned off)!
|
99 | *
|
100 | * Return status.
|
101 | */
|
102 | static long iap(long code, long p1, long p2, long p3, long p4)
|
103 | {
|
104 |
|
105 | iap_cmd[0] = code; // set command code
|
106 | iap_cmd[1] = p1; // 1st param
|
107 | iap_cmd[2] = p2; // 2nd param
|
108 | iap_cmd[3] = p3; // 3rd param
|
109 | iap_cmd[4] = p4; // 4th param
|
110 |
|
111 | //TODO
|
112 | // Sicher stellen, dass alle daten uebertragen wurden;
|
113 | // wird hier mit der warteschleife mit UART-Interrupt gemacht...
|
114 | // while (!(Intern_u0lsr&0x40)) ; // transmit last char
|
115 | _pll_off(); // disconnect PLL
|
116 | ((void (*)())0x7ffffff1)(iap_cmd, iap_res); // IAP entry point
|
117 | _pll_on(); // re-connect PLL
|
118 |
|
119 | return *iap_res; // return status
|
120 |
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 | /*Read part ID.
|
126 |
|
127 | Input: Command: code: 54
|
128 | Parameters: None
|
129 | Return: Code CMD_SUCCESS |
|
130 | Result: Result0: Part Identification Number (see Table 21302 LPC214x Part Identification numbers on page 307 for details)
|
131 | Description: This command is used to read the part identification number.
|
132 | */
|
133 | static void part_id(void)
|
134 | {
|
135 |
|
136 | if (iap(READ_PART_ID, 0, 0, 0, 0))
|
137 | {
|
138 | putstring_serial0("\n\r-- Error - Reading part ID --\n\r");
|
139 | return;
|
140 | }
|
141 |
|
142 | if (iap_res[1]==PART_ID_LPC2148)
|
143 | {putstring_serial0("\n\rPart ID: LPC2148\n\r");}
|
144 | else
|
145 | {
|
146 | putstring_serial0("\n\rPart ID (no LPC2148): ");
|
147 | put_int2str(iap_res[1]);
|
148 | putstring_serial0("\n\r");
|
149 | }
|
150 | }
|
151 |
|
152 |
|
153 |
|
154 | /*Read boot code version.
|
155 |
|
156 | Input: Command: code: 55
|
157 | Parameters: None
|
158 | Return: Code CMD_SUCCESS |
|
159 | Result: Result0: 2 bytes of boot code version number in ASCII format. It is to be interpreted as <byte1(Major)>.<byte0(Minor)>
|
160 | Description: This command is used to read the boot code version number.
|
161 | */
|
162 | long read_boot_code_version(void)
|
163 | {
|
164 | return iap(READ_BOOT_CODE_VERSION, 0, 0, 0, 0);
|
165 | }
|
166 |
|
167 |
|
168 | static void version(void)
|
169 | {
|
170 | if (read_boot_code_version())
|
171 | {
|
172 | putstring_serial0("-- Error - Reading boot code version --");
|
173 | return;
|
174 | }
|
175 | putstring_serial0("\n\rBoot code version: ");
|
176 | put_int2str((unsigned char)(iap_res[1]>>8));
|
177 | putstring_serial0(".");
|
178 | put_int2str((unsigned char)iap_res[1]);
|
179 | putstring_serial0("\n\r");
|
180 | }
|
181 |
|
182 |
|
183 |
|
184 | /*
|
185 | * Write sector.
|
186 | */
|
187 | static void s_write(void)
|
188 | {
|
189 | static char data[512] = {'T','E','S','T'}; // data buffer
|
190 |
|
191 | // If not blank, dump sector data.
|
192 | if (iap(BLANK_CHECK_SECTOR, SECT, SECT, 0, 0) == SECTOR_NOT_BLANK)
|
193 | {
|
194 | putstring_serial0("\nSector not blank!\n");
|
195 | return;
|
196 | }
|
197 |
|
198 | putstring_serial0("\n\rEnter data (single RETURN to abort):");
|
199 |
|
200 |
|
201 | if (prepare_sector( SECT, SECT ))
|
202 | {
|
203 | putstring_serial0("\n\r-- Error: PREPARE_SECTOR_FOR_WRITE_OPERATION: ");
|
204 | return;
|
205 | }
|
206 | if (copy_ram_to_flash( ADDR, (long)data, sizeof(data)))
|
207 | {
|
208 | putstring_serial0("\n\r-- Error: COPY_RAM_TO_FLASH: ");
|
209 | put_int2str((int)copy_ram_to_flash( ADDR, (long)data, sizeof(data)));
|
210 | putstring_serial0(" --\n\r");
|
211 | return;
|
212 | }
|
213 | if (compare(ADDR,(long)data, sizeof(data)))
|
214 | {
|
215 | putstring_serial0("\n\r-- Error: COMPARE --\n\r");
|
216 | return;
|
217 | }
|
218 |
|
219 | putstring_serial0("\n\rData successfully written.\n\r");
|
220 | }
|
221 |
|
222 |
|
223 | /*Copy Ram to Flash
|
224 |
|
225 | Input: Command: code: 51
|
226 | Param0: (DST): Destination Flash address where data bytes are to be written. This address should be a 256 byte boundary.
|
227 | Param1: (SRC): Source RAM address from which data bytes are to be read. This address should be a word boundary.
|
228 | Param2: Number of bytes to be written. Should be 256 | 512 | 1024 | 4096.
|
229 | Param3: System Clock Frequency (CCLK) in kHz.
|
230 | Return: Code CMD_SUCCESS |
|
231 | SRC_ADDR_ERROR (Address not a word boundary) |
|
232 | DST_ADDR_ERROR (Address not on correct boundary) |
|
233 | SRC_ADDR_NOT_MAPPED |
|
234 | DST_ADDR_NOT_MAPPED |
|
235 | COUNT_ERROR (Byte count is not 256 | 512 | 1024 | 4096) |
|
236 | SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION |
|
237 | BUSY |
|
238 | Result: None
|
239 | Description: This command is used to program the flash memory. The affected sectors should
|
240 | be prepared first by calling "Prepare Sector for Write Operation" command. The
|
241 | affected sectors are automatically protected again once the copy command is
|
242 | successfully executed. The boot sector can not be written by this command.
|
243 | */
|
244 | long copy_ram_to_flash( long tmp_adr_dst,long tmp_adr_src, long tmp_size )
|
245 | {
|
246 | return iap(COPY_RAM_TO_FLASH, tmp_adr_dst, tmp_adr_src, tmp_size, _XTAL);
|
247 | }
|
248 |
|
249 |
|
250 |
|
251 | /*Compare
|
252 |
|
253 | Input: Command: code: 56
|
254 | Param0: (DST): Starting Flash or RAM address of data bytes to be compared. This address should be a word boundary.
|
255 | Param1: (SRC): Starting Flash or RAM address of data bytes to be compared. This address should be a word boundary.
|
256 | Param2: Number of bytes to be compared; should be a multiple of 4.
|
257 | Return: Code CMD_SUCCESS |
|
258 | COMPARE_ERROR |
|
259 | COUNT_ERROR (Byte count is not a multiple of 4) |
|
260 | ADDR_ERROR |
|
261 | ADDR_NOT_MAPPED
|
262 | Result: Result0: Offset of the first mismatch if the Status Code is COMPARE_ERROR.
|
263 | Description: This command is used to compare the memory contents at two locations.
|
264 | The result may not be correct when the source or destination includes any
|
265 | of the first 64 bytes starting from address zero. The first 64 bytes can be
|
266 | re-mapped to RAM.
|
267 | */
|
268 | long compare(long tmp_adr_dst,long tmp_adr_src, long tmp_size)
|
269 | {
|
270 | return iap(COMPARE, tmp_adr_dst, tmp_adr_src, tmp_size, 0);
|
271 | }
|
272 |
|
273 |
|
274 |
|
275 | // Erase sector.
|
276 | static void s_erase(void)
|
277 | {
|
278 | // If blank, skip erase.
|
279 | if (!blank_check_sector(SECT,SECT))
|
280 | {
|
281 | putstring_serial0("\n\rSector already blank!\n\r");
|
282 | return;
|
283 | }
|
284 |
|
285 | if (prepare_sector( SECT, SECT ))
|
286 | {putstring_serial0("\n\r-- Error: PREPARE_SECTOR_FOR_WRITE_OPERATION --\n\r");
|
287 | return;}
|
288 | if (erase( SECT, SECT ))
|
289 | {putstring_serial0("\n\r-- Error: ERASE_SECTOR --\n\r");
|
290 | return;}
|
291 | if (blank_check_sector(SECT,SECT))
|
292 | {putstring_serial0("\n\r-- Error: BLANK_CHECK_SECTOR --\n\r");
|
293 | return;}
|
294 |
|
295 | putstring_serial0("\n\rSector successfully erased.\n\r");
|
296 | }
|
297 |
|
298 |
|
299 |
|
300 | /*Prepare sector(s) for write operation
|
301 |
|
302 | Input: Command: code: 50
|
303 | Param0: Start Sector Number
|
304 | Param1: End Sector Number (should be greater than or equal to start sector number).
|
305 | Return Code CMD_SUCCESS |
|
306 | BUSY |
|
307 | INVALID_SECTOR
|
308 | Result None
|
309 | Description: This command must be executed before executing "Copy RAM to Flash" or
|
310 | "Erase Sector(s)" command. Successful execution of the "Copy RAM to Flash" or
|
311 | "Erase Sector(s)" command causes relevant sectors to be protected again. The
|
312 | boot sector can not be prepared by this command.
|
313 | */
|
314 | long prepare_sector( long tmp_sect1, long tmp_sect2 )
|
315 | {
|
316 | return iap(PREPARE_SECTOR_FOR_WRITE_OPERATION, tmp_sect1, tmp_sect2, 0, 0);
|
317 | }
|
318 |
|
319 |
|
320 |
|
321 | /*erase
|
322 |
|
323 | Input: Command: code: 52
|
324 | Param0: Start Sector Number
|
325 | Param1: End Sector Number (should be greater than or equal to start sector number).
|
326 | Param2: System Clock Frequency (CCLK) in kHz.
|
327 | Return: Code CMD_SUCCESS |
|
328 | BUSY |
|
329 | SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION |
|
330 | INVALID_SECTOR
|
331 | Result: None
|
332 | Description: This command is used to erase a sector or multiple sectors of on-chip Flash
|
333 | memory. The boot sector can not be erased by this command.
|
334 | */
|
335 | long erase(long tmp_sect1, long tmp_sect2 )
|
336 | {
|
337 | return iap(ERASE_SECTOR, tmp_sect1, tmp_sect2, _XTAL, 0);
|
338 | }
|
339 |
|
340 |
|
341 | /*Blank Check Sector
|
342 |
|
343 | Input: Command: code: 53
|
344 | Param0: Start Sector Number
|
345 | Param1: End Sector Number (should be greater than or equal to start sector number).
|
346 | Return: Code CMD_SUCCESS |
|
347 | BUSY |
|
348 | SECTOR_NOT_BLANK |
|
349 | INVALID_SECTOR
|
350 | Result: Result0: Offset of the first non blank word location if the Status Code is SECTOR_NOT_BLANK.
|
351 | Result1: Contents of non blank word location.
|
352 | Description: This command is used to blank check a sector or multiple sectors of on-chip Flash
|
353 | memory. To blank check a single sector use the same "Start" and "End" sector numbers.
|
354 | */
|
355 | long blank_check_sector(long tmp_sect1, long tmp_sect2)
|
356 | {
|
357 | return iap(BLANK_CHECK_SECTOR, tmp_sect1, tmp_sect2, 0, 0);
|
358 | }
|
359 |
|
360 |
|
361 | /*
|
362 | * Switch CPU to standard XTAL
|
363 | */
|
364 | void _pll_off(void)
|
365 | {
|
366 | //TODO
|
367 | PLLCON = 0x00;
|
368 | feed();
|
369 | }
|
370 |
|
371 | /*
|
372 | * Switch to Original CPU-XTAL
|
373 | */
|
374 | void _pll_on(void)
|
375 | {
|
376 | //TODO
|
377 | // Enabling the PLL */
|
378 | PLLCON = 0x1;
|
379 | feed();
|
380 |
|
381 | // Wait for the PLL to lock to set frequency
|
382 | while(!(PLLSTAT & 0x400)) ;
|
383 |
|
384 | // Connect the PLL as the clock source
|
385 | PLLCON = 0x3;
|
386 | feed();
|
387 | }
|