iap_fkt.c


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 21–302 “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
}