Ну потому обычно и грузят загрузчик первым, он проверяет контрольную сумму прошивки, и если что не переходит на нее. В вашей же схеме залей вы кривую программу (в момент переписывания из рам во флэш), после ресета проц превратиться в кирпич. Естественно после записи программы во флэш ее стоит проверить, что записалось именно то что хотели, но стремление 100% записи понятно.
вот у меня такой IAP, это LPCешный, с некоторыми правками, в частности переделаны макросы запрета прерывания
/*****************************************************************************
* $Id$
*
* Project: NXP LPC1700 Secondary Bootloader Example
*
* Description: Provides access to In-Application Programming (IAP) routines
* contained within the bootROM sector of LPC1100 devices.
*
* Copyright© 2010, NXP Semiconductor
* All rights reserved.
*
*****************************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
*****************************************************************************/
#include "IAP.h"
#include <LPC17xx.h>
#include <string.h>
/* IAP Command Definitions */
#define IAP_CMD_PREPARE_SECTORS 50
#define IAP_CMD_COPY_RAM_TO_FLASH 51
#define IAP_CMD_ERASE_SECTORS 52
#define IAP_CMD_BLANK_CHECK_SECTORS 53
#define IAP_CMD_READ_PART_ID 54
#define IAP_CMD_READ_BOOT_ROM_VERSION 55
#define IAP_CMD_COMPARE 56
#define IAP_CMD_REINVOKE_ISP 57
#define IAP_CMD_READ_SERIAL_NUMBER 58
/* IAP boot ROM location and access function */
#define IAP_ROM_LOCATION 0x1FFF1FF1UL
#define IAP_EXECUTE_CMD(a,

((void (*)())(IAP_ROM_LOCATION))(a,

//макрос запрета прерывания с сохранением статуса
#define INTERRUPT_DISABLE_STORE(flag1, flag2) (flag1) = __disable_irq(); (flag2) = __disable_fiq()
//макрос восстановления статуса прерывания
#define INTERRUPT_RESTORE(flag1, flag2) if(!(flag1)) __enable_irq(); if(!(flag2)) __enable_fiq()
/*****************************************************************************
** Function name: u32IAP_PrepareSectors
**
** Description: Prepares sector(s) for erasing or write operations. This
** command must be executed before executing the "Copy RAM to
** Flash" or "Erase Sector(s)" commands.
**
** Parameters: u32StartSector - Number of first sector to prepare.
** u32EndSector - Number of last sector to prepare.
**
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_PrepareSectors(uint32_t u32StartSector, uint32_t u32EndSector)
{
uint32_t u32Status;
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
if (u32EndSector < u32StartSector)
{
u32Status = IAP_STA_INVALD_PARAM;
}
else
{
au32Command[0] = IAP_CMD_PREPARE_SECTORS;
au32Command[1] = u32StartSector;
au32Command[2] = u32EndSector;
IAP_EXECUTE_CMD(au32Command, au32Result);
u32Status = au32Result[0];
}
INTERRUPT_RESTORE(IRQ, FIQ);
return u32Status;
}
/*****************************************************************************
** Function name: u32IAP_CopyRAMToFlash
**
** Description: Program the flash memory with data stored in RAM.
**
** Parameters: u32DstAddr - Destination Flash address, should be a 256
** byte boundary.
** u32SrcAddr - Source RAM address, should be a word boundary
** u32Len - Number of 8-bit bytes to write, must be 256
** 512, 1024, or 4096.
*
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_CopyRAMToFlash(uint32_t u32DstAddr, uint32_t u32SrcAddr, uint32_t u32Len)
{
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
au32Command[0] = IAP_CMD_COPY_RAM_TO_FLASH;
au32Command[1] = u32DstAddr;
au32Command[2] = u32SrcAddr;
au32Command[3] = u32Len;
au32Command[4] = SystemCoreClock / 1000UL; /* Core clock frequency in kHz */
IAP_EXECUTE_CMD(au32Command, au32Result);
INTERRUPT_RESTORE(IRQ, FIQ);
return au32Result[0];
}
/*****************************************************************************
** Function name: u32IAP_EraseSectors
**
** Description: Erase a sector or multiple sectors of on-chip Flash memory.
**
** Parameters: u32StartSector - Number of first sector to erase.
** u32EndSector - Number of last sector to erase.
*
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_EraseSectors(uint32_t u32StartSector, uint32_t u32EndSector)
{
uint32_t u32Status;
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
if (u32EndSector < u32StartSector)
{
u32Status = IAP_STA_INVALD_PARAM;
}
else
{
au32Command[0] = IAP_CMD_ERASE_SECTORS;
au32Command[1] = u32StartSector;
au32Command[2] = u32EndSector;
au32Command[3] = SystemCoreClock / 1000UL; /* Core clock frequency in kHz */
IAP_EXECUTE_CMD(au32Command, au32Result);
u32Status = au32Result[0];
}
INTERRUPT_RESTORE(IRQ, FIQ);
return u32Status;
}
/*****************************************************************************
** Function name: u32IAP_BlankCheckSectors
**
** Description: Blank check a sector or multiple sectors of on-chip flash
** memory.
**
** Parameters: u32StartSector - Number of first sector to check.
** u32EndSector - Number of last sector to check.
** pu32Result[0] - Offset of the first non blank word location
** if the Status Code is IAP_STA_SECTOR_NOT_BLANK.
** pu32Result[1] - Contents of non blank word location.
**
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_BlankCheckSectors(uint32_t u32StartSector, uint32_t u32EndSector, uint32_t *pu32Result)
{
uint32_t u32Status;
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
if (u32EndSector < u32StartSector)
{
u32Status = IAP_STA_INVALD_PARAM;
}
else
{
au32Command[0] = IAP_CMD_BLANK_CHECK_SECTORS;
au32Command[1] = u32StartSector;
au32Command[2] = u32EndSector;
IAP_EXECUTE_CMD(au32Command, au32Result);
if (au32Result[0] == IAP_STA_SECTOR_NOT_BLANK)
{
*pu32Result = au32Result[0];
*(pu32Result + 1) = au32Result[1];
}
u32Status = au32Result[0];
}
INTERRUPT_RESTORE(IRQ, FIQ);
return u32Status;
}
/*****************************************************************************
** Function name: u32IAP_ReadPartID
**
** Description: Read the part identification number.
**
** Parameters: pu32PartID - Pointer to storage for part ID number.
*
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_ReadPartID(uint32_t *pu32PartID)
{
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
au32Command[0] = IAP_CMD_READ_PART_ID;
IAP_EXECUTE_CMD(au32Command, au32Result);
*pu32PartID = au32Result[1];
INTERRUPT_RESTORE(IRQ, FIQ);
return au32Result[0];
}
/*****************************************************************************
** Function name: u32IAP_ReadBootVersion
**
** Description: Read the boot code version number.
**
** Parameters: pu32Major - Major version number in ASCII format.
** pu32Minor - Minor version number in ASCII format.
**
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_ReadBootVersion(uint32_t *pu32Major, uint32_t *pu32Minor)
{
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
au32Command[0] = IAP_CMD_READ_BOOT_ROM_VERSION;
IAP_EXECUTE_CMD(au32Command, au32Result);
*pu32Major = (au32Result[1] & 0x0000FF00UL) >> 8;
*pu32Minor = au32Result[1] & 0x000000FFUL;
INTERRUPT_RESTORE(IRQ, FIQ);
return au32Result[0];
}
/*****************************************************************************
** Function name: u32IAP_ReadBootVersion
**
** Description: Read the boot code version number.
**
** Parameters: pu32Major - Major version number in ASCII format.
** pu32Minor - Minor version number in ASCII format.
**
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
void u32IAP_ReadSerialNumber(uint32_t *pu32byte0, uint32_t *pu32byte1,
uint32_t *pu32byte2, uint32_t *pu32byte3)
{
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
au32Command[0] = IAP_CMD_READ_SERIAL_NUMBER;
IAP_EXECUTE_CMD(au32Command, au32Result);
*pu32byte0 = au32Result[0];
*pu32byte1 = au32Result[1];
*pu32byte2 = au32Result[2];
*pu32byte3 = au32Result[3];
INTERRUPT_RESTORE(IRQ, FIQ);
return;
}
/*****************************************************************************
** Function name: u32IAP_Compare
**
** Description: Compares the memory contents at two locations.
**
** Parameters: u32Len - Number of bytes to compare, must be a multiple of 4.
** pu32Offset - Offset of the first mismatch if the Status Code is COMPARE_ERROR
**
** Returned value: Status code returned by IAP ROM function.
**
******************************************************************************/
uint32_t u32IAP_Compare(uint32_t u32DstAddr, uint32_t u32SrcAddr, uint32_t u32Len, uint32_t *pu32Offset)
{
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
au32Command[0] = IAP_CMD_COMPARE;
au32Command[1] = u32DstAddr;
au32Command[2] = u32SrcAddr;
au32Command[3] = u32Len;
IAP_EXECUTE_CMD(au32Command, au32Result);
if (au32Result[0] == IAP_STA_COMPARE_ERROR)
{
if (pu32Offset != 0)
{
*pu32Offset = au32Result[1];
}
}
INTERRUPT_RESTORE(IRQ, FIQ);
return au32Result[0];
}
/*****************************************************************************
** Function name: vIAP_ReinvokeISP
**
** Description: Invoke the bootloader in ISP mode.
**
** Parameters: None.
*
** Returned value: None.
**
******************************************************************************/
void vIAP_ReinvokeISP(void)
{
uint32_t au32Result[5];
uint32_t au32Command[5];
uint32_t IRQ; uint32_t FIQ;
INTERRUPT_DISABLE_STORE(IRQ, FIQ);
au32Command[0] = IAP_CMD_REINVOKE_ISP;
IAP_EXECUTE_CMD(au32Command, au32Result);
INTERRUPT_RESTORE(IRQ, FIQ);
}
/*****************************************************************************
** End Of File
*****************************************************************************/
и к нему вот такой файл с функциями вызова, он приложения зависимый, но я надеюсь вы разберетесь, кстати в нем я обнаружил еще коменты, что массивы которые в память перепихиваются должны быть выровнены по 32 бита, важный момент в работе с флэш. Сектора у меня стираются по командно и пишутся по блоков, так что между вызовами есть пауза порядка миллисекунды.
там еще есть хедеры, они просто константы описывают, надеюсь из названия констант будет понятно что они значат%). Поглядите, может вам поможет, может найдете какие отличия. У меня сколько не пробовал пишет прошивку и пользовательские данные без глюков. А в начале глюки были.