Statistics
| Branch: | Tag: | Revision:

amiro-blt / Target / Source / ARMCM4_STM32 / flash.c @ a8fc89f4

History | View | Annotate | Download (31.746 KB)

1
/************************************************************************************//**
2
* \file         Source\ARMCM4_STM32\flash.c
3
* \brief        Bootloader flash driver source file.
4
* \ingroup      Target_ARMCM4_STM32
5
* \internal
6
*----------------------------------------------------------------------------------------
7
*                          C O P Y R I G H T
8
*----------------------------------------------------------------------------------------
9
*   Copyright (c) 2013  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
#include "stm32f4xx.h"                           /* STM32 registers                    */
39
#include "stm32f4xx_conf.h"                      /* STM32 peripheral drivers           */
40

    
41

    
42
/****************************************************************************************
43
* Macro definitions
44
****************************************************************************************/
45
/** \brief Value for an invalid flash sector. */
46
#define FLASH_INVALID_SECTOR            (0xff)
47
/** \brief Value for an invalid flash address. */
48
#define FLASH_INVALID_ADDRESS           (0xffffffff)
49
/** \brief Standard size of a flash block for writing. */
50
#define FLASH_WRITE_BLOCK_SIZE          (512)
51
/** \brief Total numbers of sectors in array flashLayout[]. */
52
#define FLASH_TOTAL_SECTORS             (sizeof(flashLayout)/sizeof(flashLayout[0]))
53
/** \brief Offset into the user program's vector table where the checksum is located. */
54
#define FLASH_VECTOR_TABLE_CS_OFFSET    (0x1ac)
55

    
56

    
57
/****************************************************************************************
58
* Type definitions
59
****************************************************************************************/
60
/** \brief Flash sector descriptor type. */
61
typedef struct 
62
{
63
  blt_addr   sector_start;                       /**< sector start address             */
64
  blt_int32u sector_size;                        /**< sector size in bytes             */
65
  blt_int8u  sector_num;                         /**< sector number                    */
66
} tFlashSector;
67

    
68
/** \brief    Structure type for grouping flash block information.
69
 *  \details  Programming is done per block of max FLASH_WRITE_BLOCK_SIZE. for this a 
70
 *            flash block manager is implemented in this driver. this flash block manager
71
 *            depends on this flash block info structure. It holds the base address of 
72
 *            the flash block and the data that should be programmed into the flash 
73
 *            block. The .base_addr must be a multiple of FLASH_WRITE_BLOCK_SIZE.
74
 */
75
typedef struct
76
{
77
  blt_addr  base_addr;
78
  blt_int8u data[FLASH_WRITE_BLOCK_SIZE];
79
} tFlashBlockInfo;
80

    
81

    
82
/****************************************************************************************
83
* Function prototypes
84
****************************************************************************************/
85
static blt_bool  FlashInitBlock(tFlashBlockInfo *block, blt_addr address);
86
static tFlashBlockInfo *FlashSwitchBlock(tFlashBlockInfo *block, blt_addr base_addr);
87
static blt_bool  FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, 
88
                                 blt_int8u *data, blt_int32u len);
89
static blt_bool  FlashWriteBlock(tFlashBlockInfo *block);
90
static blt_bool  FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector);
91
static blt_int8u FlashGetSector(blt_addr address);
92

    
93

    
94
/****************************************************************************************
95
* Local constant declarations
96
****************************************************************************************/
97
/** \brief   Array wit the layout of the flash memory.
98
 *  \details Also controls what part of the flash memory is reserved for the bootloader. 
99
 *           If the bootloader size changes, the reserved sectors for the bootloader 
100
 *           might need adjustment to make sure the bootloader doesn't get overwritten.
101
 */
102
static const tFlashSector flashLayout[] =
103
{
104
  /* space is reserved for a bootloader configuration with all supported communication
105
   * interfaces enabled. when for example only UART is needed, than the space required
106
   * for the bootloader can be made a lot smaller here.
107
   */
108
  /* { 0x08000000, 0x04000,  0},           flash sector  0 - reserved for bootloader   */
109
  /* { 0x08004000, 0x04000,  1},           flash sector  1 - reserved for bootloader   */
110
  { 0x08008000, 0x04000,  2},           /* flash sector  2 - 16kb                      */
111
  { 0x0800c000, 0x04000,  3},           /* flash sector  3 -  16kb                     */
112
  { 0x08010000, 0x10000,  4},           /* flash sector  4 -  64kb                     */
113
  { 0x08020000, 0x20000,  5},           /* flash sector  5 - 128kb                     */
114
  { 0x08040000, 0x20000,  6},           /* flash sector  6 - 128kb                     */
115
  { 0x08060000, 0x20000,  7},           /* flash sector  7 - 128kb                     */
116
#if (BOOT_NVM_SIZE_KB > 512)
117
  { 0x08080000, 0x20000,  8},           /* flash sector  8 - 128kb                     */
118
  { 0x080A0000, 0x20000,  9},           /* flash sector  9 - 128kb                     */
119
  { 0x080C0000, 0x20000, 10},           /* flash sector 10 - 128kb                     */
120
  { 0x080E0000, 0x20000, 11},           /* flash sector 11 - 128kb                     */
121
#endif
122
#if (BOOT_NVM_SIZE_KB > 1024)
123
  { 0x08100000, 0x04000, 12},           /* flash sector 12 -  16kb                     */
124
  { 0x08104000, 0x04000, 13},           /* flash sector 13 -  16kb                     */
125
  { 0x08108000, 0x04000, 14},           /* flash sector 14 -  16kb                     */
126
  { 0x0810c000, 0x04000, 15},           /* flash sector 15 -  16kb                     */
127
  { 0x08110000, 0x10000, 16},           /* flash sector 16 -  64kb                     */
128
  { 0x08120000, 0x20000, 17},           /* flash sector 17 - 128kb                     */
129
  { 0x08140000, 0x20000, 18},           /* flash sector 18 - 128kb                     */
130
  { 0x08160000, 0x20000, 19},           /* flash sector 19 - 128kb                     */
131
  { 0x08180000, 0x20000, 20},           /* flash sector 20 - 128kb                     */
132
  { 0x081A0000, 0x20000, 21},           /* flash sector 21 - 128kb                     */
133
  { 0x081C0000, 0x20000, 22},           /* flash sector 22 - 128kb                     */
134
  { 0x081E0000, 0x20000, 23},           /* flash sector 23 - 128kb                     */
135
#endif
136
#if (BOOT_NVM_SIZE_KB > 2048)
137
#error "BOOT_NVM_SIZE_KB > 2048 is currently not supported."
138
#endif
139
};
140

    
141
/** \brief   Lookup table to quickly convert sector number to mask.
142
 *  \details The STM32F4x Standard Peripheral Library driver needs a sector mask instead
143
 *           of the sector number. this ROM lookup table can quickly convert the sector
144
 *           number to its mask.
145
 */
146
static const blt_int16u flashSectorNumToMask[] =
147
{
148
  FLASH_Sector_0,                        /* idx 0  - mask for sector 0                 */
149
  FLASH_Sector_1,                        /* idx 1  - mask for sector 1                 */
150
  FLASH_Sector_2,                        /* idx 2  - mask for sector 2                 */
151
  FLASH_Sector_3,                        /* idx 3  - mask for sector 3                 */
152
  FLASH_Sector_4,                        /* idx 4  - mask for sector 4                 */
153
  FLASH_Sector_5,                        /* idx 5  - mask for sector 5                 */
154
  FLASH_Sector_6,                        /* idx 6  - mask for sector 6                 */
155
  FLASH_Sector_7,                        /* idx 7  - mask for sector 7                 */
156
  FLASH_Sector_8,                        /* idx 8  - mask for sector 8                 */
157
  FLASH_Sector_9,                        /* idx 9  - mask for sector 9                 */
158
  FLASH_Sector_10,                       /* idx 10 - mask for sector 10                */
159
  FLASH_Sector_11,                       /* idx 11 - mask for sector 11                */
160
  FLASH_Sector_12,                       /* idx 12 - mask for sector 12                */
161
  FLASH_Sector_13,                       /* idx 13 - mask for sector 13                */
162
  FLASH_Sector_14,                       /* idx 14 - mask for sector 14                */
163
  FLASH_Sector_15,                       /* idx 15 - mask for sector 15                */
164
  FLASH_Sector_16,                       /* idx 16 - mask for sector 16                */
165
  FLASH_Sector_17,                       /* idx 17 - mask for sector 17                */
166
  FLASH_Sector_18,                       /* idx 18 - mask for sector 18                */
167
  FLASH_Sector_19,                       /* idx 19 - mask for sector 19                */
168
  FLASH_Sector_20,                       /* idx 20 - mask for sector 20                */
169
  FLASH_Sector_21,                       /* idx 21 - mask for sector 21                */
170
  FLASH_Sector_22,                       /* idx 22 - mask for sector 22                */
171
  FLASH_Sector_23                        /* idx 23 - mask for sector 23                */
172
};
173

    
174

    
175
/****************************************************************************************
176
* Local data declarations
177
****************************************************************************************/
178
/** \brief   Local variable with information about the flash block that is currently
179
 *           being operated on.
180
 *  \details The smallest amount of flash that can be programmed is 
181
 *           FLASH_WRITE_BLOCK_SIZE. A flash block manager is implemented in this driver
182
 *           and stores info in this variable. Whenever new data should be flashed, it
183
 *           is first added to a RAM buffer, which is part of this variable. Whenever
184
 *           the RAM buffer, which has the size of a flash block, is full or  data needs
185
 *           to be written to a different block, the contents of the RAM buffer are 
186
 *           programmed to flash. The flash block manager requires some software 
187
 *           overhead, yet results is faster flash programming because data is first 
188
 *           harvested, ideally until there is enough to program an entire flash block, 
189
 *           before the flash device is actually operated on.
190
 */
191
static tFlashBlockInfo blockInfo;
192

    
193
/** \brief   Local variable with information about the flash boot block.
194
 *  \details The first block of the user program holds the vector table, which on the 
195
 *           STM32 is also the where the checksum is written to. Is it likely that 
196
 *           the vector table is first flashed and then, at the end of the programming
197
 *           sequence, the checksum. This means that this flash block need to be written
198
 *           to twice. Normally this is not a problem with flash memory, as long as you
199
 *           write the same values to those bytes that are not supposed to be changed 
200
 *           and the locations where you do write to are still in the erased 0xFF state.
201
 *           Unfortunately, writing twice to flash this way, does not work reliably on 
202
 *           all micros. This is why we need to have an extra block, the bootblock,
203
 *           placed under the management of the block manager. This way is it possible 
204
 *           to implement functionality so that the bootblock is only written to once
205
 *           at the end of the programming sequence.
206
 */
207
static tFlashBlockInfo bootBlockInfo;
208

    
209

    
210
/************************************************************************************//**
211
** \brief     Initializes the flash driver. 
212
** \return    none.
213
**
214
****************************************************************************************/
215
void FlashInit(void)
216
{
217
  /* init the flash block info structs by setting the address to an invalid address */
218
  blockInfo.base_addr = FLASH_INVALID_ADDRESS;
219
  bootBlockInfo.base_addr = FLASH_INVALID_ADDRESS;
220
} /*** end of FlashInit ***/
221

    
222

    
223
/************************************************************************************//**
224
** \brief     Writes the data to flash through a flash block manager. Note that this
225
**            function also checks that no data is programmed outside the flash 
226
**            memory region, so the bootloader can never be overwritten.
227
** \param     addr Start address.
228
** \param     len  Length in bytes.
229
** \param     data Pointer to the data buffer.
230
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
231
**
232
****************************************************************************************/
233
blt_bool FlashWrite(blt_addr addr, blt_int32u len, blt_int8u *data)
234
{
235
  blt_addr base_addr;
236

    
237
  /* make sure the addresses are within the flash device */
238
  if ( (FlashGetSector(addr) == FLASH_INVALID_SECTOR) || \
239
       (FlashGetSector(addr+len-1) == FLASH_INVALID_SECTOR) )
240
  {
241
    return BLT_FALSE;       
242
  }
243

    
244
  /* if this is the bootblock, then let the boot block manager handle it */
245
  base_addr = (addr/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE;
246
  if (base_addr == flashLayout[0].sector_start)
247
  {
248
    /* let the boot block manager handle it */
249
    return FlashAddToBlock(&bootBlockInfo, addr, data, len);
250
  }
251
  /* let the block manager handle it */
252
  return FlashAddToBlock(&blockInfo, addr, data, len);
253
} /*** end of FlashWrite ***/
254

    
255

    
256
/************************************************************************************//**
257
** \brief     Erases the flash memory. Note that this function also checks that no 
258
**            data is erased outside the flash memory region, so the bootloader can 
259
**            never be erased.
260
** \param     addr Start address.
261
** \param     len  Length in bytes.
262
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
263
**
264
****************************************************************************************/
265
blt_bool FlashErase(blt_addr addr, blt_int32u len)
266
{
267
  blt_int8u first_sector;
268
  blt_int8u last_sector;
269
  
270
  /* obtain the first and last sector number */
271
  first_sector = FlashGetSector(addr);
272
  last_sector  = FlashGetSector(addr+len-1);
273
  /* check them */
274
  if ( (first_sector == FLASH_INVALID_SECTOR) || (last_sector == FLASH_INVALID_SECTOR) )
275
  {
276
    return BLT_FALSE;
277
  }
278
  /* erase the sectors */
279
  return FlashEraseSectors(first_sector, last_sector);
280
} /*** end of FlashErase ***/
281

    
282

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

    
316
  /* first check that the bootblock contains valid data. if not, this means the
317
   * bootblock is not part of the reprogramming this time and therefore no
318
   * new checksum needs to be written
319
   */
320
   if (bootBlockInfo.base_addr == FLASH_INVALID_ADDRESS)
321
   {
322
    return BLT_TRUE;
323
   }
324

    
325
  /* compute the checksum. note that the user program's vectors are not yet written
326
   * to flash but are present in the bootblock data structure at this point.
327
   */
328
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x00]));
329
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x04]));
330
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x08]));
331
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x0C]));
332
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x10]));
333
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x14]));
334
  signature_checksum += *((blt_int32u*)(&bootBlockInfo.data[0+0x18]));
335
  signature_checksum  = ~signature_checksum; /* one's complement */
336
  signature_checksum += 1; /* two's complement */
337

    
338
  /* write the checksum */
339
  return FlashWrite(flashLayout[0].sector_start+FLASH_VECTOR_TABLE_CS_OFFSET, 
340
                    sizeof(blt_addr), (blt_int8u*)&signature_checksum);
341
} /*** end of FlashWriteChecksum ***/
342

    
343

    
344
/************************************************************************************//**
345
** \brief     Verifies the checksum, which indicates that a valid user program is
346
**            present and can be started.
347
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
348
**
349
****************************************************************************************/
350
blt_bool FlashVerifyChecksum(void)
351
{
352
  blt_int32u signature_checksum = 0;
353
  
354
  /* verify the checksum based on how it was written by CpuWriteChecksum() */
355
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start));
356
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x04));
357
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x08));
358
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x0C));
359
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x10));
360
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x14));
361
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+0x18));
362
  signature_checksum += *((blt_int32u*)(flashLayout[0].sector_start+FLASH_VECTOR_TABLE_CS_OFFSET));
363
  /* sum should add up to an unsigned 32-bit value of 0 */
364
  if (signature_checksum == 0)
365
  {
366
    /* checksum okay */
367
    return BLT_TRUE;
368
  }
369
  /* checksum incorrect */
370
  return BLT_FALSE;
371
} /*** end of FlashVerifyChecksum ***/
372

    
373

    
374
/************************************************************************************//**
375
** \brief     Finalizes the flash driver operations. There could still be data in
376
**            the currently active block that needs to be flashed.
377
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
378
**
379
****************************************************************************************/
380
blt_bool FlashDone(void)
381
{
382
  /* check if there is still data waiting to be programmed in the boot block */
383
  if (bootBlockInfo.base_addr != FLASH_INVALID_ADDRESS)
384
  {
385
    if (FlashWriteBlock(&bootBlockInfo) == BLT_FALSE)
386
    {
387
      return BLT_FALSE;
388
    }
389
  }
390
  
391
  /* check if there is still data waiting to be programmed */
392
  if (blockInfo.base_addr != FLASH_INVALID_ADDRESS)
393
  {
394
    if (FlashWriteBlock(&blockInfo) == BLT_FALSE)
395
    {
396
      return BLT_FALSE;
397
    }
398
  }
399
  /* still here so all is okay */  
400
  return BLT_TRUE;
401
} /*** end of FlashDone ***/
402

    
403

    
404
/************************************************************************************//**
405
** \brief     Obtains the base address of the flash memory available to the user program.
406
**            This is basically the first address in the flashLayout table.
407
** \return    Base address.
408
**
409
****************************************************************************************/
410
blt_addr FlashGetUserProgBaseAddress(void)
411
{
412
  return flashLayout[0].sector_start;
413
} /*** end of FlashGetUserProgBaseAddress ***/
414

    
415

    
416
/************************************************************************************//**
417
** \brief     Copies data currently in flash to the block->data and sets the 
418
**            base address.
419
** \param     block   Pointer to flash block info structure to operate on.
420
** \param     address Base address of the block data.
421
** \return    BLT_TRUE if successful, BLT_FALSE otherwise. 
422
**
423
****************************************************************************************/
424
static blt_bool FlashInitBlock(tFlashBlockInfo *block, blt_addr address)
425
{
426
  /* check address alignment */  
427
  if ((address % FLASH_WRITE_BLOCK_SIZE) != 0)
428
  {
429
    return BLT_FALSE;
430
  }
431
  /* make sure that we are initializing a new block and not the same one */
432
  if (block->base_addr == address)
433
  {
434
    /* block already initialized, so nothing to do */
435
    return BLT_TRUE;
436
  }
437
  /* set the base address and copies the current data from flash */  
438
  block->base_addr = address;  
439
  CpuMemCopy((blt_addr)block->data, address, FLASH_WRITE_BLOCK_SIZE);
440
  return BLT_TRUE;
441
} /*** end of FlashInitBlock ***/
442

    
443

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

    
482
  /* initialize tne new block when necessary */
483
  if (FlashInitBlock(block, base_addr) == BLT_FALSE) 
484
  {
485
    return BLT_NULL;
486
  }
487

    
488
  /* still here to all is okay  */
489
  return block;
490
} /*** end of FlashSwitchBlock ***/
491

    
492

    
493
/************************************************************************************//**
494
** \brief     Programming is done per block. This function adds data to the block
495
**            that is currently collecting data to be written to flash. If the
496
**            address is outside of the current block, the current block is written
497
**            to flash an a new block is initialized.
498
** \param     block   Pointer to flash block info structure to operate on.
499
** \param     address Flash destination address.
500
** \param     data    Pointer to the byte array with data.
501
** \param     len     Number of bytes to add to the block.
502
** \return    BLT_TRUE if successful, BLT_FALSE otherwise.
503
**
504
****************************************************************************************/
505
static blt_bool FlashAddToBlock(tFlashBlockInfo *block, blt_addr address, 
506
                                blt_int8u *data, blt_int32u len)
507
{
508
  blt_addr   current_base_addr;
509
  blt_int8u  *dst;
510
  blt_int8u  *src;
511
  
512
  /* determine the current base address */
513
  current_base_addr = (address/FLASH_WRITE_BLOCK_SIZE)*FLASH_WRITE_BLOCK_SIZE;
514

    
515
  /* make sure the blockInfo is not uninitialized */
516
  if (block->base_addr == FLASH_INVALID_ADDRESS)
517
  {
518
    /* initialize the blockInfo struct for the current block */
519
    if (FlashInitBlock(block, current_base_addr) == BLT_FALSE)
520
    {
521
      return BLT_FALSE;
522
    }
523
  }
524

    
525
  /* check if the new data fits in the current block */
526
  if (block->base_addr != current_base_addr)
527
  {
528
    /* need to switch to a new block, so program the current one and init the next */
529
    block = FlashSwitchBlock(block, current_base_addr);
530
    if (block == BLT_NULL)
531
    {
532
      return BLT_FALSE;
533
    }
534
  }
535
  
536
  /* add the data to the current block, but check for block overflow */
537
  dst = &(block->data[address - block->base_addr]);
538
  src = data;
539
  do
540
  {
541
    /* keep the watchdog happy */
542
    CopService();
543
    /* buffer overflow? */
544
    if ((blt_addr)(dst-&(block->data[0])) >= FLASH_WRITE_BLOCK_SIZE)
545
    {
546
      /* need to switch to a new block, so program the current one and init the next */
547
      block = FlashSwitchBlock(block, current_base_addr+FLASH_WRITE_BLOCK_SIZE);
548
      if (block == BLT_NULL)
549
      {
550
        return BLT_FALSE;
551
      }
552
      /* reset destination pointer */
553
      dst = &(block->data[0]);
554
    }
555
    /* write the data to the buffer */
556
    *dst = *src;
557
    /* update pointers */
558
    dst++;
559
    src++;
560
    /* decrement byte counter */
561
    len--;
562
  }
563
  while (len > 0);
564
  /* still here so all is good */
565
  return BLT_TRUE;
566
} /*** end of FlashAddToBlock ***/
567

    
568

    
569
/************************************************************************************//**
570
** \brief     Programs FLASH_WRITE_BLOCK_SIZE bytes to flash from the block->data
571
**            array.
572
** \param     block   Pointer to flash block info structure to operate on.
573
** \return    BLT_TRUE if successful, BLT_FALSE otherwise.
574
**
575
****************************************************************************************/
576
static blt_bool FlashWriteBlock(tFlashBlockInfo *block)
577
{
578
  blt_int8u  sector_num;
579
  blt_bool   result = BLT_TRUE;
580
  blt_addr   prog_addr;
581
  blt_int32u prog_data;
582
  blt_int32u word_cnt;
583

    
584
  /* check that address is actually within flash */
585
  sector_num = FlashGetSector(block->base_addr);
586
  if (sector_num == FLASH_INVALID_SECTOR)
587
  {
588
    return BLT_FALSE;
589
  }
590
  /* unlock the flash array */
591
  FLASH_Unlock();
592
  /* clear pending flags (if any) */  
593
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
594
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
595
  /* check that the flash peripheral is not busy */
596
  if (FLASH_GetStatus() == FLASH_BUSY)
597
  {
598
    /* lock the flash array again */
599
    FLASH_Lock(); 
600
    /* could not perform erase operation */
601
    return BLT_FALSE;
602
  }
603
  /* program all words in the block one by one */
604
  for (word_cnt=0; word_cnt<(FLASH_WRITE_BLOCK_SIZE/sizeof(blt_int32u)); word_cnt++)
605
  {
606
    prog_addr = block->base_addr + (word_cnt * sizeof(blt_int32u));
607
    prog_data = *(volatile blt_int32u*)(&block->data[word_cnt * sizeof(blt_int32u)]);
608
    /* keep the watchdog happy */
609
    CopService();
610
    /* program the word */
611
    if (FLASH_ProgramWord(prog_addr, prog_data) != FLASH_COMPLETE)
612
    {
613
      result = BLT_FALSE;
614
      break;
615
    }
616
    /* verify that the written data is actually there */
617
    if (*(volatile blt_int32u*)prog_addr != prog_data)
618
    {
619
      result = BLT_FALSE;
620
      break;
621
    }
622
  }
623
  /* lock the flash array again */
624
  FLASH_Lock(); 
625
  /* still here so all is okay */
626
  return result;
627
} /*** end of FlashWriteBlock ***/
628

    
629

    
630
/************************************************************************************//**
631
** \brief     Erases the flash sectors from first_sector up until last_sector.
632
** \param     first_sector First flash sector number.
633
** \param     last_sector  Last flash sector number.
634
** \return    BLT_TRUE if successful, BLT_FALSE otherwise.
635
**
636
****************************************************************************************/
637
static blt_bool FlashEraseSectors(blt_int8u first_sector, blt_int8u last_sector)
638
{
639
  blt_int8u sector_cnt;
640

    
641
  /* validate the sector numbers */
642
  if (first_sector > last_sector)
643
  {
644
    return BLT_FALSE;
645
  }
646
  if ( (first_sector < flashLayout[0].sector_num) || \
647
       (last_sector > flashLayout[FLASH_TOTAL_SECTORS-1].sector_num) )
648
  {
649
    return BLT_FALSE;
650
  }
651
  /* unlock the flash array */
652
  FLASH_Unlock();
653
  /* clear pending flags (if any) */  
654
  FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | 
655
                  FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR); 
656
  /* check that the flash peripheral is not busy */
657
  if (FLASH_GetStatus() == FLASH_BUSY)
658
  {
659
    /* lock the flash array again */
660
    FLASH_Lock(); 
661
    /* could not perform erase operation */
662
    return BLT_FALSE;
663
  }
664
  /* erase all sectors one by one */
665
  for (sector_cnt=first_sector; sector_cnt<= last_sector; sector_cnt++)
666
  {
667
    /* keep the watchdog happy */
668
    CopService();
669
    /* submit the sector erase request */
670
    if (FLASH_EraseSector(flashSectorNumToMask[sector_cnt], VoltageRange_3) != FLASH_COMPLETE)
671
    {
672
      /* lock the flash array again */
673
      FLASH_Lock(); 
674
      /* could not perform erase operation */
675
      return BLT_FALSE;
676
    }
677
  }
678
  /* lock the flash array again */
679
  FLASH_Lock(); 
680
  /* still here so all went okay */
681
  return BLT_TRUE;
682
} /*** end of FlashEraseSectors ***/
683

    
684

    
685
/************************************************************************************//**
686
** \brief     Determines the flash sector the address is in.
687
** \param     address Address in the flash sector.
688
** \return    Flash sector number or FLASH_INVALID_SECTOR.
689
**
690
****************************************************************************************/
691
static blt_int8u FlashGetSector(blt_addr address)
692
{
693
  blt_int8u sectorIdx;
694
  
695
  /* search through the sectors to find the right one */
696
  for (sectorIdx = 0; sectorIdx < FLASH_TOTAL_SECTORS; sectorIdx++)
697
  {
698
    /* keep the watchdog happy */
699
    CopService();
700
    /* is the address in this sector? */
701
    if ( (address >= flashLayout[sectorIdx].sector_start) && \
702
         (address < (flashLayout[sectorIdx].sector_start + \
703
                  flashLayout[sectorIdx].sector_size)) )
704
    {
705
      /* return the sector number */
706
      return flashLayout[sectorIdx].sector_num;
707
    }
708
  }
709
  /* still here so no valid sector found */
710
  return FLASH_INVALID_SECTOR;
711
} /*** end of FlashGetSector ***/
712

    
713

    
714
/*********************************** end of flash.c ************************************/