318 lines
10 KiB
C
318 lines
10 KiB
C
|
/**********************************************************************
|
||
|
* $Id$ lpc_iap.c 2011-11-21
|
||
|
*//**
|
||
|
* @file lpc_iap.c
|
||
|
* @brief Contains all functions support for IAP on LPC
|
||
|
* @version 1.0
|
||
|
* @date 21. November. 2011
|
||
|
* @author NXP MCU SW Application Team
|
||
|
*
|
||
|
* Copyright(C) 2011, 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.
|
||
|
* Permission to use, copy, modify, and distribute this software and its
|
||
|
* documentation is hereby granted, under NXP Semiconductors'
|
||
|
* relevant copyright in the software, without fee, provided that it
|
||
|
* is used in conjunction with NXP Semiconductors microcontrollers. This
|
||
|
* copyright, permission, and disclaimer notice must appear in all copies of
|
||
|
* this code.
|
||
|
**********************************************************************/
|
||
|
#ifdef __BUILD_WITH_EXAMPLE__
|
||
|
#include "lpc_libcfg.h"
|
||
|
#else
|
||
|
#include "lpc_libcfg_default.h"
|
||
|
#endif /* __BUILD_WITH_EXAMPLE__ */
|
||
|
#ifdef _IAP
|
||
|
#include "lpc_iap.h"
|
||
|
#include "lpc_clkpwr.h"
|
||
|
|
||
|
// IAP Command
|
||
|
typedef void (*IAP)(uint32_t *cmd,uint32_t *result);
|
||
|
IAP iap_entry = (IAP) IAP_LOCATION;
|
||
|
#define IAP_Call iap_entry
|
||
|
|
||
|
/** @addtogroup IAP_Public_Functions LCD Public Function
|
||
|
* @ingroup IAP
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Get Sector Number
|
||
|
*
|
||
|
* @param[in] adr Sector Address
|
||
|
*
|
||
|
* @return Sector Number.
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
uint32_t GetSecNum (uint32_t adr)
|
||
|
{
|
||
|
uint32_t n;
|
||
|
|
||
|
n = adr >> 12; // 4kB Sector
|
||
|
if (n >= 0x10) {
|
||
|
n = 0x0E + (n >> 3); // 32kB Sector
|
||
|
}
|
||
|
|
||
|
return (n); // Sector Number
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Prepare sector(s) for write operation
|
||
|
*
|
||
|
* @param[in] start_sec The number of start sector
|
||
|
* @param[in] end_sec The number of end sector
|
||
|
*
|
||
|
* @return CMD_SUCCESS/BUSY/INVALID_SECTOR.
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE PrepareSector(uint32_t start_sec, uint32_t end_sec)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
command.cmd = IAP_PREPARE; // Prepare Sector for Write
|
||
|
command.param[0] = start_sec; // Start Sector
|
||
|
command.param[1] = end_sec; // End Sector
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Copy RAM to Flash
|
||
|
*
|
||
|
* @param[in] dest destination buffer (in Flash memory).
|
||
|
* @param[in] source source buffer (in RAM).
|
||
|
* @param[in] size the write size.
|
||
|
*
|
||
|
* @return CMD_SUCCESS.
|
||
|
* SRC_ADDR_ERROR/DST_ADDR_ERROR
|
||
|
* SRC_ADDR_NOT_MAPPED/DST_ADDR_NOT_MAPPED
|
||
|
* COUNT_ERROR/SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION
|
||
|
* BUSY
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE CopyRAM2Flash(uint8_t * dest, uint8_t* source, IAP_WRITE_SIZE size)
|
||
|
{
|
||
|
uint32_t sec;
|
||
|
IAP_STATUS_CODE status;
|
||
|
IAP_COMMAND_Type command;
|
||
|
|
||
|
// Prepare sectors
|
||
|
sec = GetSecNum((uint32_t)dest);
|
||
|
status = PrepareSector(sec, sec);
|
||
|
if(status != CMD_SUCCESS)
|
||
|
return status;
|
||
|
|
||
|
// write
|
||
|
command.cmd = IAP_COPY_RAM2FLASH; // Copy RAM to Flash
|
||
|
command.param[0] = (uint32_t)dest; // Destination Flash Address
|
||
|
command.param[1] = (uint32_t)source; // Source RAM Address
|
||
|
command.param[2] = size; // Number of bytes
|
||
|
command.param[3] = CLKPWR_GetCLK(CLKPWR_CLKTYPE_CPU) / 1000; // CCLK in kHz
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
|
||
|
return (IAP_STATUS_CODE)command.status; // Finished without Errors
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Erase sector(s)
|
||
|
*
|
||
|
* @param[in] start_sec The number of start sector
|
||
|
* @param[in] end_sec The number of end sector
|
||
|
*
|
||
|
* @return CMD_SUCCESS.
|
||
|
* INVALID_SECTOR
|
||
|
* SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION
|
||
|
* BUSY
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE EraseSector(uint32_t start_sec, uint32_t end_sec)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
IAP_STATUS_CODE status;
|
||
|
|
||
|
// Prepare sectors
|
||
|
status = PrepareSector(start_sec, end_sec);
|
||
|
if(status != CMD_SUCCESS)
|
||
|
return status;
|
||
|
|
||
|
// Erase sectors
|
||
|
command.cmd = IAP_ERASE; // Prepare Sector for Write
|
||
|
command.param[0] = start_sec; // Start Sector
|
||
|
command.param[1] = end_sec; // End Sector
|
||
|
command.param[2] = CLKPWR_GetCLK(CLKPWR_CLKTYPE_CPU) / 1000; // CCLK in kHz
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Blank check sector(s)
|
||
|
*
|
||
|
* @param[in] start_sec The number of start sector
|
||
|
* @param[in] end_sec The number of end sector
|
||
|
* @param[out] first_nblank_loc The offset of the first non-blank word
|
||
|
* @param[out] first_nblank_val The value of the first non-blank word
|
||
|
*
|
||
|
* @return CMD_SUCCESS.
|
||
|
* INVALID_SECTOR
|
||
|
* SECTOR_NOT_BLANK
|
||
|
* BUSY
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE BlankCheckSector(uint32_t start_sec, uint32_t end_sec,
|
||
|
uint32_t *first_nblank_loc,
|
||
|
uint32_t *first_nblank_val)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
|
||
|
command.cmd = IAP_BLANK_CHECK; // Prepare Sector for Write
|
||
|
command.param[0] = start_sec; // Start Sector
|
||
|
command.param[1] = end_sec; // End Sector
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
|
||
|
if(command.status == SECTOR_NOT_BLANK)
|
||
|
{
|
||
|
// Update out value
|
||
|
if(first_nblank_loc != NULL)
|
||
|
*first_nblank_loc = command.result[0];
|
||
|
if(first_nblank_val != NULL)
|
||
|
*first_nblank_val = command.result[1];
|
||
|
}
|
||
|
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Read part identification number
|
||
|
*
|
||
|
* @param[out] partID Part ID
|
||
|
*
|
||
|
* @return CMD_SUCCESS
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE ReadPartID(uint32_t *partID)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
command.cmd = IAP_READ_PART_ID;
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
|
||
|
if(command.status == CMD_SUCCESS)
|
||
|
{
|
||
|
if(partID != NULL)
|
||
|
*partID = command.result[0];
|
||
|
}
|
||
|
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Read boot code version. The version is interpreted as <major>.<minor>.
|
||
|
*
|
||
|
* @param[out] major The major
|
||
|
* @param[out] minor The minor
|
||
|
*
|
||
|
* @return CMD_SUCCESS
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE ReadBootCodeVer(uint8_t *major, uint8_t* minor)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
command.cmd = IAP_READ_BOOT_VER;
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
|
||
|
if(command.status == CMD_SUCCESS)
|
||
|
{
|
||
|
if(major != NULL)
|
||
|
*major = (command.result[0] >> 8) & 0xFF;
|
||
|
if(minor != NULL)
|
||
|
*minor = (command.result[0]) & 0xFF;
|
||
|
}
|
||
|
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Read Device serial number.
|
||
|
*
|
||
|
* @param[out] uid Serial number.
|
||
|
*
|
||
|
* @return CMD_SUCCESS
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE ReadDeviceSerialNum(uint32_t *uid)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
command.cmd = IAP_READ_SERIAL_NUMBER;
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
|
||
|
if(command.status == CMD_SUCCESS)
|
||
|
{
|
||
|
if(uid != NULL)
|
||
|
{
|
||
|
uint32_t i = 0;
|
||
|
for(i = 0; i < 4; i++)
|
||
|
uid[i] = command.result[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief compare the memory contents at two locations.
|
||
|
*
|
||
|
* @param[in] addr1 The address of the 1st buffer (in RAM/Flash).
|
||
|
* @param[in] addr2 The address of the 2nd buffer (in RAM/Flash).
|
||
|
* @param[in] size Number of bytes to be compared; should be a multiple of 4.
|
||
|
*
|
||
|
* @return CMD_SUCCESS
|
||
|
* COMPARE_ERROR
|
||
|
* COUNT_ERROR (Byte count is not a multiple of 4)
|
||
|
* ADDR_ERROR
|
||
|
* ADDR_NOT_MAPPED
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
IAP_STATUS_CODE Compare(uint8_t *addr1, uint8_t *addr2, uint32_t size)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
command.cmd = IAP_COMPARE;
|
||
|
command.param[0] = (uint32_t)addr1;
|
||
|
command.param[1] = (uint32_t)addr2;
|
||
|
command.param[2] = size;
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
|
||
|
return (IAP_STATUS_CODE)command.status;
|
||
|
}
|
||
|
|
||
|
/*********************************************************************//**
|
||
|
* @brief Re-invoke ISP.
|
||
|
*
|
||
|
* @param[in] None.
|
||
|
*
|
||
|
* @return None.
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
void InvokeISP(void)
|
||
|
{
|
||
|
IAP_COMMAND_Type command;
|
||
|
command.cmd = IAP_REINVOKE_ISP;
|
||
|
IAP_Call (&command.cmd, &command.status); // Call IAP Command
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
|
||
|
#endif /*_IAP*/
|