Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Source / ARMCM3_STM32 / flash.c @ f7d2c786

History | View | Annotate | Download (35.515 KB)

1
/************************************************************************************//**
2
* \file         Source\ARMCM3_STM32\flash.c
3
* \brief        Bootloader flash driver source file.
4
* \ingroup      Target_ARMCM3_STM32
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2011  by Feaser    http://www.feaser.com    All rights reserved
10
*
11
*----------------------------------------------------------------------------------------
12
*                            L I C E N S E
13
*----------------------------------------------------------------------------------------
14
* This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as published by the Free
16
* Software Foundation, either version 3 of the License, or (at your option) any later
17
* version.
18
*
19
* OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
20
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
21
* PURPOSE. See the GNU General Public License for more details.
22
*
23
* You should have received a copy of the GNU General Public License along with OpenBLT.
24
* If not, see <http://www.gnu.org/licenses/>.
25
*
26
* A special exception to the GPL is included to allow you to distribute a combined work 
27
* that includes OpenBLT without being obliged to provide the source code for any 
28
* proprietary components. The exception text is included at the bottom of the license
29
* file <license.html>.
30
* 
31
* \endinternal
32
****************************************************************************************/
33

    
34
/****************************************************************************************
35
* Include files
36
****************************************************************************************/
37
#include "boot.h"                                /* bootloader generic header          */
38

    
39

    
40
/****************************************************************************************
41
* Macro definitions
42
****************************************************************************************/
43
/** \brief Value for an invalid flash sector. */
44
#define FLASH_INVALID_SECTOR            (0xff)
45
/** \brief Value for an invalid flash address. */
46
#define FLASH_INVALID_ADDRESS           (0xffffffff)
47
/** \brief Standard size of a flash block for writing. */
48
#define FLASH_WRITE_BLOCK_SIZE          (512)
49
/** \brief Total numbers of sectors in array flashLayout[]. */
50
#define FLASH_TOTAL_SECTORS             (sizeof(flashLayout)/sizeof(flashLayout[0]))
51
#if (BOOT_NVM_SIZE_KB > 128)
52
/** \brief Number of bytes to erase per erase operation. */
53
#define FLASH_ERASE_BLOCK_SIZE          (0x800)
54
#else
55
/** \brief Number of bytes to erase per erase operation. */
56
#define FLASH_ERASE_BLOCK_SIZE          (0x400)
57
#endif
58
/** \brief Macro for accessing the flash control registers. */
59
#define FLASH                           ((tFlashRegs *) (blt_int32u)0x40022000)
60
/** \brief Offset into the user program's vector table where the checksum is located. */
61
#define FLASH_VECTOR_TABLE_CS_OFFSET    (0x150)
62
#define FLASH_KEY1                      ((blt_int32u)0x45670123)
63
#define FLASH_KEY2                      ((blt_int32u)0xCDEF89AB)
64
#define FLASH_LOCK_BIT                  ((blt_int32u)0x00000080)
65
#define FLASH_EOP_BIT                   ((blt_int32u)0x00000020)
66
#define FLASH_PGERR_BIT                 ((blt_int32u)0x00000004)
67
#define FLASH_WRPRTERR_BIT              ((blt_int32u)0x00000010)
68
#define FLASH_BSY_BIT                   ((blt_int32u)0x00000001)
69
#define FLASH_PER_BIT                   ((blt_int32u)0x00000002)
70
#define FLASH_STRT_BIT                  ((blt_int32u)0x00000040)
71
#define FLASH_PG_BIT                    ((blt_int32u)0x00000001)
72

    
73

    
74
/****************************************************************************************
75
* Type definitions
76
****************************************************************************************/
77
/** \brief Flash sector descriptor type. */
78
typedef struct 
79
{
80
  blt_addr   sector_start;                       /**< sector start address             */
81
  blt_int32u sector_size;                        /**< sector size in bytes             */
82
  blt_int8u  sector_num;                         /**< sector number                    */
83
} tFlashSector;
84

    
85
/** \brief    Structure type for grouping flash block information.
86
 *  \details  Programming is done per block of max FLASH_WRITE_BLOCK_SIZE. for this a 
87
 *            flash block manager is implemented in this driver. this flash block manager
88
 *            depends on this flash block info structure. It holds the base address of 
89
 *            the flash block and the data that should be programmed into the flash 
90
 *            block. The .base_addr must be a multiple of FLASH_WRITE_BLOCK_SIZE.
91
 */
92
typedef struct
93
{
94
  blt_addr  base_addr;
95
  blt_int8u data[FLASH_WRITE_BLOCK_SIZE];
96
} tFlashBlockInfo;
97

    
98
/** \brief Flash controller register layout type.  */
99
typedef struct
100
{
101
  volatile blt_int32u ACR;                       /**< flash access control register    */     
102
  volatile blt_int32u KEYR;                      /**< FPEC key register                */
103
  volatile blt_int32u OPTKEYR;                   /**< flash OPTKEY register            */
104
  volatile blt_int32u SR;                        /**< flash status register            */
105
  volatile blt_int32u CR;                        /**< flash control register           */
106
  volatile blt_int32u AR;                        /**< flash address register           */
107
  volatile blt_int32u RESERVED;
108
  volatile blt_int32u OBR;                       /**< option byte register             */
109
  volatile blt_int32u WRPR;                      /**< write protection register        */
110
} tFlashRegs;                                         
111

    
112

    
113
/****************************************************************************************
114
* Function prototypes
115
****************************************************************************************/
116
static blt_bool  FlashInitBlock(tFlashBlockInfo *block, blt_addr address);
117
static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr);
118
static blt_bool  FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, 
119
                                 blt_int8u *data, blt_int32u len);
120
static blt_bool  FlashWriteBlock(tFlashBlockInfo *block);
121
static blt_bool  FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector);
122
static void      FlashUnlock(void);
123
static void      FlashLock(void);
124
static blt_int8u FlashGetSector(blt_addr address);
125
static blt_addr  FlashGetSectorBaseAddr(blt_int8u sector);
126
static blt_addr  FlashGetSectorSize(blt_int8u sector);
127

    
128

    
129
/****************************************************************************************
130
* Local constant declarations
131
****************************************************************************************/
132
/** \brief   Array wit the layout of the flash memory.
133
 *  \details Also controls what part of the flash memory is reserved for the bootloader. 
134
 *           If the bootloader size changes, the reserved sectors for the bootloader 
135
 *           might need adjustment to make sure the bootloader doesn't get overwritten.
136
 *           The current flash layout does not reflect the minimum sector size of the
137
 *           physical flash (1 - 2kb), because this would make the table quit long and
138
 *           a waste of ROM. The minimum sector size is only really needed when erasing
139
 *           the flash. This can still be done in combination with macro 
140
 *           FLASH_ERASE_BLOCK_SIZE.
141
 */
142
static const tFlashSector flashLayout[] =
143
{
144
  /* space is reserved for a bootloader configuration with all supported communication
145
   * interfaces enabled. when for example only UART is needed, than the space required
146
   * for the bootloader can be made a lot smaller here.
147
   */
148
  /* { 0x08000000, 0x02000,  0},           flash sector  0 - reserved for bootloader   */
149
  /* { 0x08002000, 0x02000,  1},           flash sector  1 - reserved for bootloader   */
150
  /* { 0x08004000, 0x02000,  2},           flash sector  2 - reserved for bootloader   */
151
  { 0x08006000, 0x02000,  3},           /* flash sector  3 - 8kb                       */
152
#if (BOOT_NVM_SIZE_KB > 32)
153
  { 0x08008000, 0x02000,  4},           /* flash sector  4 - 8kb                       */
154
  { 0x0800A000, 0x02000,  5},           /* flash sector  5 - 8kb                       */
155
  { 0x0800C000, 0x02000,  6},           /* flash sector  6 - 8kb                       */
156
  { 0x0800E000, 0x02000,  7},           /* flash sector  7 - 8kb                       */
157
#endif
158
#if (BOOT_NVM_SIZE_KB > 64)
159
  { 0x08010000, 0x02000,  8},           /* flash sector  8 - 8kb                       */
160
  { 0x08012000, 0x02000,  9},           /* flash sector  9 - 8kb                       */
161
  { 0x08014000, 0x02000, 10},           /* flash sector 10 - 8kb                       */
162
  { 0x08016000, 0x02000, 11},           /* flash sector 11 - 8kb                       */
163
  { 0x08018000, 0x02000, 12},           /* flash sector 12 - 8kb                       */
164
  { 0x0801A000, 0x02000, 13},           /* flash sector 13 - 8kb                       */
165
  { 0x0801C000, 0x02000, 14},           /* flash sector 14 - 8kb                       */
166
  { 0x0801E000, 0x02000, 15},           /* flash sector 15 - 8kb                       */
167
#endif
168
#if (BOOT_NVM_SIZE_KB > 128)
169
  { 0x08020000, 0x08000, 16},           /* flash sector 16 - 32kb                      */
170
  { 0x08028000, 0x08000, 17},           /* flash sector 17 - 32kb                      */
171
  { 0x08030000, 0x08000, 18},           /* flash sector 18 - 32kb                      */
172
  { 0x08038000, 0x08000, 19},           /* flash sector 19 - 32kb                      */
173
#endif
174
#if (BOOT_NVM_SIZE_KB > 256)
175
  { 0x08040000, 0x08000, 20},           /* flash sector 20 - 32kb                      */
176
  { 0x08048000, 0x08000, 21},           /* flash sector 21 - 32kb                      */
177
  { 0x08050000, 0x08000, 22},           /* flash sector 22 - 32kb                      */
178
  { 0x08058000, 0x08000, 23},           /* flash sector 23 - 32kb                      */
179
  { 0x08060000, 0x08000, 24},           /* flash sector 24 - 32kb                      */
180
  { 0x08068000, 0x08000, 25},           /* flash sector 25 - 32kb                      */
181
  { 0x08070000, 0x08000, 26},           /* flash sector 26 - 32kb                      */
182
  { 0x08078000, 0x08000, 27},           /* flash sector 27 - 32kb                      */
183
#endif
184
#if (BOOT_NVM_SIZE_KB > 512)
185
#error "BOOT_NVM_SIZE_KB > 512 is currently not supported."
186
#endif
187
};
188

    
189

    
190
/****************************************************************************************
191
* Local data declarations
192
****************************************************************************************/
193
/** \brief   Local variable with information about the flash block that is currently
194
 *           being operated on.
195
 *  \details The smallest amount of flash that can be programmed is 
196
 *           FLASH_WRITE_BLOCK_SIZE. A flash block manager is implemented in this driver
197
 *           and stores info in this variable. Whenever new data should be flashed, it
198
 *           is first added to a RAM buffer, which is part of this variable. Whenever
199
 *           the RAM buffer, which has the size of a flash block, is full or  data needs
200
 *           to be written to a different block, the contents of the RAM buffer are 
201
 *           programmed to flash. The flash block manager requires some software 
202
 *           overhead, yet results is faster flash programming because data is first 
203
 *           harvested, ideally until there is enough to program an entire flash block, 
204
 *           before the flash device is actually operated on.
205
 */
206
static tFlashBlockInfo blockInfo;
207

    
208
/** \brief   Local variable with information about the flash boot block.
209
 *  \details The first block of the user program holds the vector table, which on the 
210
 *           STM32 is also the where the checksum is written to. Is it likely that 
211
 *           the vector table is first flashed and then, at the end of the programming
212
 *           sequence, the checksum. This means that this flash block need to be written
213
 *           to twice. Normally this is not a problem with flash memory, as long as you
214
 *           write the same values to those bytes that are not supposed to be changed 
215
 *           and the locations where you do write to are still in the erased 0xFF state.
216
 *           Unfortunately, writing twice to flash this way, does not work reliably on 
217
 *           all micros. This is why we need to have an extra block, the bootblock,
218
 *           placed under the management of the block manager. This way is it possible 
219
 *           to implement functionality so that the bootblock is only written to once
220
 *           at the end of the programming sequence.
221
 */
222
static tFlashBlockInfo bootBlockInfo;
223

    
224

    
225
/************************************************************************************//**
226
** \brief     Initializes the flash driver. 
227
** \return    none.
228
**
229
****************************************************************************************/
230
void FlashInit(void)
231
{
232
  /* init the flash block info structs by setting the address to an invalid address */
233
  blockInfo.base_addr = FLASH_INVALID_ADDRESS;
234
  bootBlockInfo.base_addr = FLASH_INVALID_ADDRESS;
235
} /*** end of FlashInit ***/
236

    
237

    
238
/************************************************************************************//**
239
** \brief     Writes the data to flash through a flash block manager. Note that this
240
**            function also checks that no data is programmed outside the flash 
241
**            memory region, so the bootloader can never be overwritten.
242
** \param     addr Start address.
243
** \param     len  Length in bytes.
244
** \param     data Pointer to the data buffer.
245
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
246
**
247
****************************************************************************************/
248
blt_bool FlashWrite(blt_addr addr, blt_int32u len, blt_int8u *data)
249
{
250
  blt_addr base_addr;
251

    
252
  /* make sure the addresses are within the flash device */
253
  if ( (FlashGetSector(addr) == FLASH_INVALID_SECTOR) || \
254
       (FlashGetSector(addr+len-1) == FLASH_INVALID_SECTOR) )
255
  {
256
    return BLT_FALSE;       
257
  }
258

    
259
  /* if this is the bootblock, then let the boot block manager handle it */
260
  base_addr = (addr/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE;
261
  if (base_addr == flashLayout[0].sector_start)
262
  {
263
    /* let the boot block manager handle it */
264
    return FlashAddToBlock(&bootBlockInfo, addr, data, len);
265
  }
266
  /* let the block manager handle it */
267
  return FlashAddToBlock(&blockInfo, addr, data, len);
268
} /*** end of FlashWrite ***/
269

    
270

    
271
/************************************************************************************//**
272
** \brief     Erases the flash memory. Note that this function also checks that no 
273
**            data is erased outside the flash memory region, so the bootloader can 
274
**            never be erased.
275
** \param     addr Start address.
276
** \param     len  Length in bytes.
277
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
278
**
279
****************************************************************************************/
280
blt_bool FlashErase(blt_addr addr, blt_int32u len)
281
{
282
  blt_int8u first_sector;
283
  blt_int8u last_sector;
284
  
285
  /* obtain the first and last sector number */
286
  first_sector = FlashGetSector(addr);
287
  last_sector  = FlashGetSector(addr+len-1);
288
  /* check them */
289
  if ( (first_sector == FLASH_INVALID_SECTOR) || (last_sector == FLASH_INVALID_SECTOR) )
290
  {
291
    return BLT_FALSE;
292
  }
293
  /* erase the sectors */
294
  return FlashEraseSectors(first_sector, last_sector);
295
} /*** end of FlashErase ***/
296

    
297

    
298
/************************************************************************************//**
299
** \brief     Writes a checksum of the user program to non-volatile memory. This is
300
**            performed once the entire user program has been programmed. Through
301
**            the checksum, the bootloader can check if the programming session
302
**            was completed, which indicates that a valid user programming is
303
**            present and can be started.
304
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
305
**
306
****************************************************************************************/
307
blt_bool FlashWriteChecksum(void)
308
{
309
  blt_int32u signature_checksum = 0;
310
  
311
  /* for the STM32 target we defined the checksum as the Two's complement value of the
312
   * sum of the first 7 exception addresses.
313
   *
314
   * Layout of the vector table:
315
   *    0x08000000 Initial stack pointer 
316
   *    0x08000004 Reset Handler
317
   *    0x08000008 NMI Handler
318
   *    0x0800000C Hard Fault Handler
319
   *    0x08000010 MPU Fault Handler 
320
   *    0x08000014 Bus Fault Handler
321
   *    0x08000018 Usage Fault Handler
322
   *
323
   *    signature_checksum = Two's complement of (SUM(exception address values))
324
   *   
325
   *    the bootloader writes this 32-bit checksum value right after the vector table
326
   *    of the user program. note that this means one extra dummy entry must be added
327
   *    at the end of the user program's vector table to reserve storage space for the
328
   *    checksum.
329
   */
330

    
331
  /* first check that the bootblock contains valid data. if not, this means the
332
   * bootblock is not part of the reprogramming this time and therefore no
333
   * new checksum needs to be written
334
   */
335
   if (bootBlockInfo.base_addr == FLASH_INVALID_ADDRESS)
336
   {
337
    return BLT_TRUE;
338
   }
339

    
340
  /* compute the checksum. note that the user program's vectors are not yet written
341
   * to flash but are present in the bootblock data structure at this point.
342
   */
343
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x00]));
344
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x04]));
345
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x08]));
346
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x0C]));
347
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x10]));
348
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x14]));
349
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x18]));
350
  signature_checksum  = ~signature_checksum; /* one's complement */
351
  signature_checksum += 1; /* two's complement */
352

    
353
  /* write the checksum */
354
  return FlashWrite(flashLayout[0].sector_start+FLASH_VECTOR_TABLE_CS_OFFSET, 
355
                    sizeof(blt_addr), (blt_int8u*)&signature_checksum);
356
} /*** end of FlashWriteChecksum ***/
357

    
358

    
359
/************************************************************************************//**
360
** \brief     Verifies the checksum, which indicates that a valid user program is
361
**            present and can be started.
362
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
363
**
364
****************************************************************************************/
365
blt_bool FlashVerifyChecksum(void)
366
{
367
  blt_int32u signature_checksum = 0;
368
  
369
  /* verify the checksum based on how it was written by CpuWriteChecksum() */
370
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start));
371
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x04));
372
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x08));
373
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x0C));
374
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x10));
375
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x14));
376
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x18));
377
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+FLASH_VECTOR_TABLE_CS_OFFSET));
378
  /* sum should add up to an unsigned 32-bit value of 0 */
379
  if (signature_checksum == 0)
380
  {
381
    /* checksum okay */
382
    return BLT_TRUE;
383
  }
384
  /* checksum incorrect */
385
  return BLT_FALSE;
386
} /*** end of FlashVerifyChecksum ***/
387

    
388

    
389
/************************************************************************************//**
390
** \brief     Finalizes the flash driver operations. There could still be data in
391
**            the currently active block that needs to be flashed.
392
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
393
**
394
****************************************************************************************/
395
blt_bool FlashDone(void)
396
{
397
  /* check if there is still data waiting to be programmed in the boot block */
398
  if (bootBlockInfo.base_addr != FLASH_INVALID_ADDRESS)
399
  {
400
    if (FlashWriteBlock(&bootBlockInfo) == BLT_FALSE)
401
    {
402
      return BLT_FALSE;
403
    }
404
  }
405
  
406
  /* check if there is still data waiting to be programmed */
407
  if (blockInfo.base_addr != FLASH_INVALID_ADDRESS)
408
  {
409
    if (FlashWriteBlock(&blockInfo) == BLT_FALSE)
410
    {
411
      return BLT_FALSE;
412
    }
413
  }
414
  /* still here so all is okay */  
415
  return BLT_TRUE;
416
} /*** end of FlashDone ***/
417

    
418

    
419
/************************************************************************************//**
420
** \brief     Obtains the base address of the flash memory available to the user program.
421
**            This is basically the first address in the flashLayout table.
422
** \return    Base address.
423
**
424
****************************************************************************************/
425
blt_addr FlashGetUserProgBaseAddress(void)
426
{
427
  return flashLayout[0].sector_start;
428
} /*** end of FlashGetUserProgBaseAddress ***/
429

    
430

    
431
/************************************************************************************//**
432
** \brief     Copies data currently in flash to the block->data and sets the 
433
**            base address.
434
** \param     block   Pointer to flash block info structure to operate on.
435
** \param     address Base address of the block data.
436
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
437
**
438
****************************************************************************************/
439
static blt_bool FlashInitBlock(tFlashBlockInfo *block, blt_addr address)
440
{
441
  /* check address alignment */  
442
  if ((address % FLASH_WRITE_BLOCK_SIZE) != 0)
443
  {
444
    return BLT_FALSE;
445
  }
446
  /* make sure that we are initializing a new block and not the same one */
447
  if (block->base_addr == address)
448
  {
449
    /* block already initialized, so nothing to do */
450
    return BLT_TRUE;
451
  }
452
  /* set the base address and copies the current data from flash */  
453
  block->base_addr = address;  
454
  CpuMemCopy((blt_addr)block->data, address, FLASH_WRITE_BLOCK_SIZE);
455
  return BLT_TRUE;
456
} /*** end of FlashInitBlock ***/
457

    
458

    
459
/************************************************************************************//**
460
** \brief     Switches blocks by programming the current one and initializing the
461
**            next.
462
** \param     block   Pointer to flash block info structure to operate on.
463
** \param     base_addr Base address of the next block.
464
** \return    The pointer of the block info struct that is no being used, or a NULL
465
**            pointer in case of error.
466
**
467
****************************************************************************************/
468
static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr)
469
{
470
  /* check if a switch needs to be made away from the boot block. in this case the boot
471
   * block shouldn't be written yet, because this is done at the end of the programming
472
   * session by FlashDone(), this is right after the checksum was written. 
473
   */
474
  if (block == &bootBlockInfo)
475
  {
476
    /* switch from the boot block to the generic block info structure */
477
    block = &blockInfo;
478
  }
479
  /* check if a switch back into the bootblock is needed. in this case the generic block 
480
   * doesn't need to be written here yet.
481
   */
482
  else if (base_addr == flashLayout[0].sector_start)
483
  {
484
    /* switch from the generic block to the boot block info structure */
485
    block = &bootBlockInfo;
486
    base_addr = flashLayout[0].sector_start;
487
  }
488
  else
489
  {
490
    /* need to switch to a new block, so program the current one and init the next */
491
    if (FlashWriteBlock(block) == BLT_FALSE)
492
    {
493
      return BLT_NULL;
494
    }
495
  }
496

    
497
  /* initialize tne new block when necessary */
498
  if (FlashInitBlock(block, base_addr) == BLT_FALSE) 
499
  {
500
    return BLT_NULL;
501
  }
502

    
503
  /* still here to all is okay  */
504
  return block;
505
} /*** end of FlashSwitchBlock ***/
506

    
507

    
508
/************************************************************************************//**
509
** \brief     Programming is done per block. This function adds data to the block
510
**            that is currently collecting data to be written to flash. If the
511
**            address is outside of the current block, the current block is written
512
**            to flash an a new block is initialized.
513
** \param     block   Pointer to flash block info structure to operate on.
514
** \param     address Flash destination address.
515
** \param     data    Pointer to the byte array with data.
516
** \param     len     Number of bytes to add to the block.
517
** \return    BLT_TRUE if successful, BLT_FALSE otherwise.
518
**
519
****************************************************************************************/
520
static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, 
521
                                blt_int8u *data, blt_int32u len)
522
{
523
  blt_addr   current_base_addr;
524
  blt_int8u  *dst;
525
  blt_int8u  *src;
526
  
527
  /* determine the current base address */
528
  current_base_addr = (address/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE;
529

    
530
  /* make sure the blockInfo is not uninitialized */
531
  if (block->base_addr == FLASH_INVALID_ADDRESS)
532
  {
533
    /* initialize the blockInfo struct for the current block */
534
    if (FlashInitBlock(block, current_base_addr) == BLT_FALSE)
535
    {
536
      return BLT_FALSE;
537
    }
538
  }
539

    
540
  /* check if the new data fits in the current block */
541
  if (block->base_addr != current_base_addr)
542
  {
543
    /* need to switch to a new block, so program the current one and init the next */
544
    block = FlashSwitchBlock(block, current_base_addr);
545
    if (block == BLT_NULL)
546
    {
547
      return BLT_FALSE;
548
    }
549
  }
550
  
551
  /* add the data to the current block, but check for block overflow */
552
  dst = &(block->data[address - block->base_addr]);
553
  src = data;
554
  do
555
  {
556
    /* keep the watchdog happy */
557
    CopService();
558
    /* buffer overflow? */
559
    if ((blt_addr)(dst-&(block->data[0])) >= FLASH_WRITE_BLOCK_SIZE)
560
    {
561
      /* need to switch to a new block, so program the current one and init the next */
562
      block = FlashSwitchBlock(block, current_base_addr+FLASH_WRITE_BLOCK_SIZE);
563
      if (block == BLT_NULL)
564
      {
565
        return BLT_FALSE;
566
      }
567
      /* reset destination pointer */
568
      dst = &(block->data[0]);
569
    }
570
    /* write the data to the buffer */
571
    *dst = *src;
572
    /* update pointers */
573
    dst++;
574
    src++;
575
    /* decrement byte counter */
576
    len--;
577
  }
578
  while (len > 0);
579
  /* still here so all is good */
580
  return BLT_TRUE;
581
} /*** end of FlashAddToBlock ***/
582

    
583

    
584
/************************************************************************************//**
585
** \brief     Programs FLASH_WRITE_BLOCK_SIZE bytes to flash from the block->data
586
**            array.
587
** \param     block   Pointer to flash block info structure to operate on.
588
** \return    BLT_TRUE if successful, BLT_FALSE otherwise.
589
**
590
****************************************************************************************/
591
static blt_bool FlashWriteBlock(tFlashBlockInfo *block)
592
{
593
  blt_int8u  sector_num;
594
  blt_bool   result = BLT_TRUE;
595
  blt_addr   prog_addr;
596
  blt_int32u prog_data;
597
  blt_int32u word_cnt;
598

    
599
  /* check that address is actually within flash */
600
  sector_num = FlashGetSector(block->base_addr);
601
  if (sector_num == FLASH_INVALID_SECTOR)
602
  {
603
    return BLT_FALSE;
604
  }
605
  /* unlock the flash array */
606
  FlashUnlock();
607
  /* check that the flash peripheral is not busy */
608
  if ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT)
609
  {
610
    /* lock the flash array again */
611
    FlashLock();
612
    /* could not perform erase operation */
613
    return BLT_FALSE;
614
  }
615
  /* set the program bit to indicate that we are about to program data */
616
  FLASH->CR |= FLASH_PG_BIT;
617
  /* program all words in the block one by one */
618
  for (word_cnt=0; word_cnt<(FLASH_WRITE_BLOCK_SIZE/sizeof(blt_int32u)); word_cnt++)
619
  {
620
    prog_addr = block->base_addr + (word_cnt * sizeof(blt_int32u));
621
    prog_data = *(volatile blt_int32u*)(&block->data[word_cnt * sizeof(blt_int32u)]);
622
    /* program the first half word */
623
    *(volatile blt_int16u*)prog_addr = (blt_int16u)prog_data;
624
    /* wait for the program operation to complete */
625
    while ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT)
626
    {
627
      /* keep the watchdog happy */
628
      CopService();
629
    }
630
    /* program the second half word */
631
    *(volatile blt_int16u*)(prog_addr+2) = (blt_int16u)(prog_data >> 16);
632
    /* wait for the program operation to complete */
633
    while ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT)
634
    {
635
      /* keep the watchdog happy */
636
      CopService();
637
    }
638
    /* verify that the written data is actually there */
639
    if (*(volatile blt_int32u*)prog_addr != prog_data)
640
    {
641
      result = BLT_FALSE;
642
      break;
643
    }
644
  }
645
  /* reset the program bit to indicate that we are done programming data */
646
  FLASH->CR &= ~FLASH_PG_BIT;
647
  /* lock the flash array */
648
  FlashLock();
649
  /* still here so all is okay */
650
  return result;
651
} /*** end of FlashWriteBlock ***/
652

    
653

    
654
/************************************************************************************//**
655
** \brief     Erases the flash sectors from first_sector up until last_sector.
656
** \param     first_sector First flash sector number.
657
** \param     last_sector  Last flash sector number.
658
** \return    BLT_TRUE if successful, BLT_FALSE otherwise.
659
**
660
****************************************************************************************/
661
static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector)
662
{
663
  blt_int16u nr_of_blocks;
664
  blt_int16u block_cnt;
665
  blt_addr   start_addr;
666
  blt_addr   end_addr;
667

    
668
  /* validate the sector numbers */
669
  if (first_sector > last_sector)
670
  {
671
    return BLT_FALSE;
672
  }
673
  if ( (first_sector < flashLayout[0].sector_num) || \
674
       (last_sector > flashLayout[FLASH_TOTAL_SECTORS-1].sector_num) )
675
  {
676
    return BLT_FALSE;
677
  }
678
  /* unlock the flash array */
679
  FlashUnlock();
680
  /* check that the flash peripheral is not busy */
681
  if ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT)
682
  {
683
    /* lock the flash array again */
684
    FlashLock();
685
    /* could not perform erase operation */
686
    return BLT_FALSE;
687
  }
688
  /* set the page erase bit to indicate that we are about to erase a block */
689
  FLASH->CR |= FLASH_PER_BIT;
690

    
691
  /* determine how many blocks need to be erased */
692
  start_addr = FlashGetSectorBaseAddr(first_sector);
693
  end_addr = FlashGetSectorBaseAddr(last_sector) + FlashGetSectorSize(last_sector) - 1;
694
  nr_of_blocks = (end_addr - start_addr + 1) / FLASH_ERASE_BLOCK_SIZE;
695
  
696
  /* erase all blocks one by one */
697
  for (block_cnt=0; block_cnt<nr_of_blocks; block_cnt++)
698
  {
699
    /* store an address of the block that is to be erased to select the block */
700
    FLASH->AR = start_addr + (block_cnt * FLASH_ERASE_BLOCK_SIZE);
701
    /* start the block erase operation */
702
    FLASH->CR |= FLASH_STRT_BIT;
703
    /* wait for the erase operation to complete */
704
    while ((FLASH->SR & FLASH_BSY_BIT) == FLASH_BSY_BIT)
705
    {
706
      /* keep the watchdog happy */
707
      CopService();
708
    }
709
  }
710
  /* reset the page erase bit because we're all done erasing */
711
  FLASH->CR &= ~FLASH_PER_BIT;
712
  /* lock the flash array */
713
  FlashLock();
714
  /* still here so all went okay */
715
  return BLT_TRUE;
716
} /*** end of FlashEraseSectors ***/
717

    
718

    
719
/************************************************************************************//**
720
** \brief     Unlocks the flash array so that erase and program operations can be
721
**            performed.
722
** \return    none.
723
**
724
****************************************************************************************/
725
static void FlashUnlock(void)
726
{
727
  /* authorize the FPEC to access bank 1 */
728
  FLASH->KEYR = FLASH_KEY1;
729
  FLASH->KEYR = FLASH_KEY2;
730
  /* clear all possibly pending status flags */
731
  FLASH->SR = (FLASH_EOP_BIT | FLASH_PGERR_BIT | FLASH_WRPRTERR_BIT);
732
} /*** end of FlashUnlock ***/
733

    
734

    
735
/************************************************************************************//**
736
** \brief     Locks the flash array so that erase and program operations can no
737
**            longer be performed.
738
** \return    none.
739
**
740
****************************************************************************************/
741
static void FlashLock(void)
742
{
743
  /* set the lock bit to lock the FPEC */
744
  FLASH->CR |= FLASH_LOCK_BIT;
745
} /*** end of FlashLock ***/
746

    
747

    
748
/************************************************************************************//**
749
** \brief     Determines the flash sector the address is in.
750
** \param     address Address in the flash sector.
751
** \return    Flash sector number or FLASH_INVALID_SECTOR.
752
**
753
****************************************************************************************/
754
static blt_int8u FlashGetSector(blt_addr address)
755
{
756
  blt_int8u sectorIdx;
757
  
758
  /* search through the sectors to find the right one */
759
  for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++)
760
  {
761
    /* keep the watchdog happy */
762
    CopService();
763
    /* is the address in this sector? */
764
    if ( (address >= flashLayout[sectorIdx].sector_start) && \
765
         (address < (flashLayout[sectorIdx].sector_start + \
766
                  flashLayout[sectorIdx].sector_size)) )
767
    {
768
      /* return the sector number */
769
      return flashLayout[sectorIdx].sector_num;
770
    }
771
  }
772
  /* still here so no valid sector found */
773
  return FLASH_INVALID_SECTOR;
774
} /*** end of FlashGetSector ***/
775

    
776

    
777
/************************************************************************************//**
778
** \brief     Determines the flash sector base address.
779
** \param     sector Sector to get the base address of.
780
** \return    Flash sector base address or FLASH_INVALID_ADDRESS.
781
**
782
****************************************************************************************/
783
static blt_addr FlashGetSectorBaseAddr(blt_int8u sector)
784
{
785
  blt_int8u sectorIdx;
786
  
787
  /* search through the sectors to find the right one */
788
  for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++)
789
  {
790
    /* keep the watchdog happy */
791
    CopService();
792
    if (flashLayout[sectorIdx].sector_num == sector)
793
    {
794
      return flashLayout[sectorIdx].sector_start;
795
    }
796
  }
797
  /* still here so no valid sector found */
798
  return FLASH_INVALID_ADDRESS;
799
} /*** end of FlashGetSectorBaseAddr ***/
800

    
801

    
802
/************************************************************************************//**
803
** \brief     Determines the flash sector size.
804
** \param     sector Sector to get the size of.
805
** \return    Flash sector size or 0.
806
**
807
****************************************************************************************/
808
static blt_addr FlashGetSectorSize(blt_int8u sector)
809
{
810
  blt_int8u sectorIdx;
811
  
812
  /* search through the sectors to find the right one */
813
  for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++)
814
  {
815
    /* keep the watchdog happy */
816
    CopService();
817
    if (flashLayout[sectorIdx].sector_num == sector)
818
    {
819
      return flashLayout[sectorIdx].sector_size;
820
    }
821
  }
822
  /* still here so no valid sector found */
823
  return 0;
824
} /*** end of FlashGetSectorSize ***/
825

    
826

    
827
/*********************************** end of flash.c ************************************/