Jump to content

    

lpc1788 iap

Всем привет! Нужна помошь, никак не могу разобраться. Решил Я написать свой bootloader, и разместил его в конце флеша. Основная программа вызываеть его когда хочет обновиться. Сделал, все залил. Бутлодер грузиться, находит файл прошивки и должен запихать ее с нолевого адреса флеша. Но при записи(256 512 байит или более)портиться первый две или три пачки, пишиться какаято чушь, а далее все как положено записываеться.Сектора флеша форматирую перед записью. Может кто сталкивался с проблемой???

Share this post


Link to post
Share on other sites

1. Лучше наоборот сделать%)

Бутлоадер в начало положить, а прошивку боевую ближе к концу.

Стартуете с бутлоадера, он проверяет прошивку боевую (целостность и прочее), если все ок переходит к ней,если нет ждет новую.

 

Ну не важно...

 

2. Была такая фигня (на 1768, но они близнецы братья как понимаю) , нужно запрещать прерывания, если брали стандартные примеры, то там есть запреты, но вместо них пустые заглушки, а иногда ваще нет запретов. А запреты ОЧЕНЬ строго нужны. Даже таймер может сбивать процесс.

Share this post


Link to post
Share on other sites
1. Лучше наоборот сделать%)

Бутлоадер в начало положить, а прошивку боевую ближе к концу.

Стартуете с бутлоадера, он проверяет прошивку боевую (целостность и прочее), если все ок переходит к ней,если нет ждет новую.

Идея была в том, что бутлодел заливает прошивку и просто ресетит микроконтроллер и он весело стартует с новой прошивкой

 

2. Была такая фигня (на 1768, но они близнецы братья как понимаю) , нужно запрещать прерывания, если брали стандартные примеры, то там есть запреты, но вместо них пустые заглушки, а иногда ваще нет запретов. А запреты ОЧЕНЬ строго нужны. Даже таймер может сбивать процесс.

Прерывания отрубаю, таблицы векторов перемешаю. В errata вычитал что нужно в Pboost тройку вставить и в Matrix arb еденицу в бит rom lat, не помогло !

Как Я понял из errata что еще частоту можно понизить и типо все пучком будет.

Share this post


Link to post
Share on other sites

Почему не работает, не знаю, но прокомментирую саму реализацию. Размещать бутлоадер в конце вполне разумно, у меня так же сделано. Но идея вызывать загрузчик из приложения не очень хорошая. Тут многие сталкивались с проблемами при таком подходе и в итоге переходили к другой схеме: сначала всегда стартует загрузчик и проверяет, нужно ли обновлять приложение или стартовать имеющееся.

Share this post


Link to post
Share on other sites
Почему не работает, не знаю, но прокомментирую саму реализацию. Размещать бутлоадер в конце вполне разумно, у меня так же сделано. Но идея вызывать загрузчик из приложения не очень хорошая. Тут многие сталкивались с проблемами при таком подходе и в итоге переходили к другой схеме: сначала всегда стартует загрузчик и проверяет, нужно ли обновлять приложение или стартовать имеющееся.

Вот скорей всего так и буду делать, размешать в начале и проверять есть чего или нет.

А причина почему вызываю загрузчик из приложения, что бы уменьшить код загрузчика. В основном приложении гружу прошивку в SDRAM через USB, прыгаю на загрузчик, на всё готовое, инициализированное =). И просто копирую с SDRAM в буфер в RAMe, кусочками по 256 байт и пишу во флеш.

 

Просто обидно, хочется разобрать в причинах нестабильной работе IAP, а то он так в середине флеша напишет мне лабуду, а Я потом буду гадать, чего это основная программа падает.

Share this post


Link to post
Share on other sites

Ну потому обычно и грузят загрузчик первым, он проверяет контрольную сумму прошивки, и если что не переходит на нее. В вашей же схеме залей вы кривую программу (в момент переписывания из рам во флэш), после ресета проц превратиться в кирпич. Естественно после записи программы во флэш ее стоит проверить, что записалось именно то что хотели, но стремление 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, B)			((void (*)())(IAP_ROM_LOCATION))(a, B)

//макрос запрета прерывания с сохранением статуса
#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 бита, важный момент в работе с флэш. Сектора у меня стираются по командно и пишутся по блоков, так что между вызовами есть пауза порядка миллисекунды.

 

/*****************************************************************************
*****************************************************************************/
#include "IAP.h"
#include "IntFlashRoutines.h"
#include "dbg_cfg.h"
#include "general.h"

#include <LPC17xx.h>
#include <string.h>


const uint32_t sector_start_map[MAX_FLASH_SECTOR] = {SECTOR_0_START,             \
SECTOR_1_START,SECTOR_2_START,SECTOR_3_START,SECTOR_4_START,SECTOR_5_START,      \
SECTOR_6_START,SECTOR_7_START,SECTOR_8_START,SECTOR_9_START,SECTOR_10_START,     \
SECTOR_11_START,SECTOR_12_START,SECTOR_13_START,SECTOR_14_START,SECTOR_15_START, \
SECTOR_16_START,SECTOR_17_START,SECTOR_18_START,SECTOR_19_START,SECTOR_20_START, \
SECTOR_21_START,SECTOR_22_START,SECTOR_23_START,SECTOR_24_START,SECTOR_25_START, \
SECTOR_26_START,SECTOR_27_START,SECTOR_28_START,SECTOR_29_START					 };

const uint32_t sector_end_map[MAX_FLASH_SECTOR] = {SECTOR_0_END,SECTOR_1_END,    \
SECTOR_2_END,SECTOR_3_END,SECTOR_4_END,SECTOR_5_END,SECTOR_6_END,SECTOR_7_END,   \
SECTOR_8_END,SECTOR_9_END,SECTOR_10_END,SECTOR_11_END,SECTOR_12_END,             \
SECTOR_13_END,SECTOR_14_END,SECTOR_15_END,SECTOR_16_END,SECTOR_17_END,           \
SECTOR_18_END,SECTOR_19_END,SECTOR_20_END,SECTOR_21_END,SECTOR_22_END,           \
SECTOR_23_END,SECTOR_24_END,SECTOR_25_END,SECTOR_26_END,                         \
SECTOR_27_END,SECTOR_28_END,SECTOR_29_END										 };


//const unsigned crp __attribute__((section(".ARM.__at_0x2FC"))) = CRP;
/*****************************************************************************
******************************************************************************/
//----------------------------------------------------------//
#pragma inline
void ReadCPUSerialNumber(uint32_t *pu32byte0, uint32_t *pu32byte1,
							 uint32_t *pu32byte2, uint32_t *pu32byte3)
{
 u32IAP_ReadSerialNumber(pu32byte0, pu32byte1, pu32byte2, pu32byte3);
}
//----------------------------------------------------------//
#pragma inline
uint32_t ReadCPUPartID(uint32_t *pu32PartID)
{
 return(u32IAP_ReadPartID(pu32PartID));
}

//----------------------------------------------------------//
//----------------------------------------------------------//
uint32_t WriteSettingsToFlash(uint8_t *data, uint16_t length)
{
 uint32_t rez = 0;
uint32_t i; //параметр цикла
//массив для записи во флэш, выровненный по 32 бита, для записи блоками по 256 байт
uint32_t AlignData[FLASH_BLOCK_SIZE / 4];

//нулевая длинна данных, ошибка
 if(length == 0) return 1000;



 /*	Prepare Sectors to be flashed, erese them */
 rez = EraseSettingsFlashSegment(); //стираем данные настроек
if( rez != IAP_STA_CMD_SUCCESS) 
	return rez; //возвращаем код ошибки

 //записываем и проверяем запись блоками
for(i = 0; i < length; i += FLASH_BLOCK_SIZE) 
{
	//очищаем массив, чтобы хвост данных записался дополненный нулями
	memset(AlignData, 0, FLASH_BLOCK_SIZE); 
	if((length - i) > FLASH_BLOCK_SIZE) //если данных больше чем на блок
		memcpy(AlignData, (data + i), FLASH_BLOCK_SIZE); //копируем целый блок
	else
		memcpy(AlignData, (data + i), (length - i)); //копируем только конец данных	

	/*	Prepare Sectors to be flashed */
	rez = u32IAP_PrepareSectors(SETTINGS_DATA_SECTOR, SETTINGS_DATA_SECTOR);
	if( rez != IAP_STA_CMD_SUCCESS) 
		return (PREPARE2_SECTOR_ERR+rez);//2000

	/*	Copy data (already) located in RAM to flash */
	//размер данных в байтах, пишем целыми 256 байтными блоками
	rez = u32IAP_CopyRAMToFlash((SETTINGS_DATA_FLASH_START + i), (uint32_t)AlignData, FLASH_BLOCK_SIZE); 
	if( rez != IAP_STA_CMD_SUCCESS) 
		return (COPY_RAM_TO_FLASH_ERR+rez); //4000

	/*	Verify the flash contents with the contents in RAM */
	//размер данных в байтах, проверяем целыми 256 байтными блоками
	rez = u32IAP_Compare((SETTINGS_DATA_FLASH_START + i), (uint32_t)AlignData, FLASH_BLOCK_SIZE, 0); 
	if( rez != IAP_STA_CMD_SUCCESS) 
		return (COMPARE_SECTOR_ERR+rez); //5000
}

//возвращаем результат - все хорошо	
return rez;
}

/*****************************************************************************
******************************************************************************/
void  ReadSettingsFromFlash( uint8_t * DstAddr, uint32_t nBytes)
{
 memcpy( DstAddr, (uint8_t *)(SETTINGS_DATA_FLASH_START) , nBytes );
}
/*****************************************************************************
******************************************************************************/
//----------------------------------------------------------//
uint32_t EraseSettingsFlashSegment( void )
{
 uint32_t rez = 0;

 /*	Prepare Sectors to be erased */ 
 rez = u32IAP_PrepareSectors(SETTINGS_DATA_SECTOR, SETTINGS_DATA_SECTOR);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (PREPARE1_SECTOR_ERR+rez);

 rez = u32IAP_EraseSectors(SETTINGS_DATA_SECTOR, SETTINGS_DATA_SECTOR);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (ERASE_SECTOR_ERR+rez);

 return rez;
}
//----------------------------------------------------------//
//----------------------------------------------------------//
uint32_t WriteEthSettingsToFlash(uint8_t *data, uint16_t length)
{
 uint32_t rez = 0;
uint32_t i;  //параметр цикла
//массив для записи во флэш, выровненный по 32 бита, для записи блоками по 256 байт
uint32_t AlignData[FLASH_BLOCK_SIZE / 4]; 


//нулевая длинна данных, ошибка
 if(length == 0) return 1000;


 /*	Prepare Sectors to be flashed */
 rez = EraseEthSettingsFlashSegment(); //стираем данные настроек езернет
if( rez != IAP_STA_CMD_SUCCESS) 
	return rez; //возвращаем код ошибки


//записываем и проверяем запись блоками
for(i = 0; i < length; i += FLASH_BLOCK_SIZE) 
{
	//очищаем массив, чтобы хвост данных записался дополненный нулями
	memset(AlignData, 0, FLASH_BLOCK_SIZE); 
	if((length - i) > FLASH_BLOCK_SIZE) //если данных больше чем на блок
		memcpy(AlignData, (data + i), FLASH_BLOCK_SIZE); //копируем целый блок
	else
		memcpy(AlignData, (data + i), (length - i)); //копируем только конец данных	

   /*	Prepare Sectors to be flashed */
   rez = u32IAP_PrepareSectors(ETH_SETTINGS_SECTOR, ETH_SETTINGS_SECTOR);
   if( rez != IAP_STA_CMD_SUCCESS) 
		return (PREPARE2_SECTOR_ERR+rez);//2000


	/*	Copy data (already) located in RAM to flash */
	//размер данных в байтах, пишем целыми 256 байтными блоками
	rez = u32IAP_CopyRAMToFlash((ETH_SETTINGS_FLASH_START + i), (uint32_t)AlignData, FLASH_BLOCK_SIZE); 
	if( rez != IAP_STA_CMD_SUCCESS) 
		return (COPY_RAM_TO_FLASH_ERR+rez); //4000

	/*	Verify the flash contents with the contents in RAM */
	//размер данных в байтах, проверяем целыми 256 байтными блоками
	rez = u32IAP_Compare((ETH_SETTINGS_FLASH_START + i), (uint32_t)AlignData, FLASH_BLOCK_SIZE, 0); 
	if( rez != IAP_STA_CMD_SUCCESS) 
		return (COMPARE_SECTOR_ERR+rez); //5000
 }

//возвращаем результат
 return rez;
}

/*****************************************************************************
******************************************************************************/
void  ReadEthSettingsFromFlash( uint8_t * DstAddr, uint32_t nBytes)
{
 memcpy( DstAddr, (uint8_t *)(ETH_SETTINGS_FLASH_START) , nBytes );
}
/*****************************************************************************
******************************************************************************/
//----------------------------------------------------------//
uint32_t EraseEthSettingsFlashSegment( void )
{
 uint32_t rez = 0;


 /*	Prepare Sectors to be erased */ 
 rez = u32IAP_PrepareSectors(ETH_SETTINGS_SECTOR, ETH_SETTINGS_SECTOR);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (PREPARE1_SECTOR_ERR+rez);

 rez = u32IAP_EraseSectors(ETH_SETTINGS_SECTOR, ETH_SETTINGS_SECTOR);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (ERASE_SECTOR_ERR+rez);

 return rez;
}

//----------------------------------------------------------//
//----------------------------------------------------------//
uint32_t WriteUserDataToFlash(uint8_t sector_sellect, uint8_t block_sellect, uint8_t *data, uint16_t length)
{
 uint32_t rez = 0;
uint32_t AlignData[FLASH_BLOCK_SIZE / 4]; //буфер для 32 битного выравнивания данных для флэш 

if(sector_sellect >= USER_DATA_SIZE)
	return WRONG_SECTOR_SELLECT; //выходим с ошибкой

 if(block_sellect >= BLOCK_NUM_IN_SECTOR)
	return WRONG_BLOCK_SELLECT; //выходим с ошибкой

 if(length == 0) 
	return 1000;


//запись идет максимально 1 блоком, если данных больше, конец отбрасываем
if(length > FLASH_BLOCK_SIZE)
	length = FLASH_BLOCK_SIZE;

 /*	Prepare Sectors to be flashed */
 rez = u32IAP_PrepareSectors((USER_DATA_SECTOR + sector_sellect), (USER_DATA_SECTOR + sector_sellect));
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (PREPARE1_SECTOR_ERR+rez);//1000

memset((uint8_t *)AlignData, 0, FLASH_BLOCK_SIZE); //обнуляем буфер
 /*	Copy data (already) located in RAM to flash */
 memcpy((uint8_t *)AlignData, data, length ); //копируем данные, оставшаяся часть будет 0


 /*	Copy data (already) located in RAM to flash */
 rez = u32IAP_CopyRAMToFlash((sector_start_map[uSER_DATA_SECTOR + sector_sellect] + block_sellect * FLASH_BLOCK_SIZE) , (uint32_t)AlignData, FLASH_BLOCK_SIZE);	
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (COPY_RAM_TO_FLASH_ERR+rez); //4000

 /*	Verify the flash contents with the contents in RAM */
 rez = u32IAP_Compare((sector_start_map[uSER_DATA_SECTOR + sector_sellect] + block_sellect * FLASH_BLOCK_SIZE), (uint32_t)AlignData, FLASH_BLOCK_SIZE, 0);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (COMPARE_SECTOR_ERR+rez); //5000

 return rez;
}

/*****************************************************************************
******************************************************************************/
uint32_t  ReadUserDataFromFlash(uint8_t sector_sellect, uint8_t block_sellect, uint8_t * DstAddr)
{

if(sector_sellect >= USER_DATA_SIZE)
	return WRONG_SECTOR_SELLECT; //выходим с ошибкой

 if(block_sellect >= BLOCK_NUM_IN_SECTOR)
	return WRONG_BLOCK_SELLECT; //выходим с ошибкой

//читаем данные из блока
memcpy( DstAddr, (uint8_t *)(sector_start_map[uSER_DATA_SECTOR + sector_sellect] + block_sellect * FLASH_BLOCK_SIZE), FLASH_BLOCK_SIZE);

return 0; //выходим из функции
}
/*****************************************************************************
******************************************************************************/
//----------------------------------------------------------//
uint32_t EraseUserDataFlashSegment(uint8_t sector_sellect)
{
 uint32_t rez = 0;


if(sector_sellect >= USER_DATA_SIZE)
	return WRONG_SECTOR_SELLECT; //выходим с ошибкой

 /*	Prepare Sectors to be erased */ 
 rez = u32IAP_PrepareSectors((USER_DATA_SECTOR + sector_sellect), (USER_DATA_SECTOR + sector_sellect));
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (PREPARE1_SECTOR_ERR+rez);

 rez = u32IAP_EraseSectors((USER_DATA_SECTOR + sector_sellect), (USER_DATA_SECTOR + sector_sellect));
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (ERASE_SECTOR_ERR+rez);

return rez;
}

//функция проверки наличия данных настройки езернета 
/*****************************************************************************
Return 1 if Code present
Return 0 if Code NOT present
******************************************************************************/
uint32_t  CheckForPresentEthSettingsData(void)
{
 uint32_t Result[2];


 if ( u32IAP_BlankCheckSectors(ETH_SETTINGS_SECTOR, ETH_SETTINGS_SECTOR, Result) == IAP_STA_CMD_SUCCESS )
   return (0);
 else
   return (BLANK_CHECK_SECTOR_ERR);
}

//функция проверки наличия данных настройки 
/*****************************************************************************
Return 1 if Code present
Return 0 if Code NOT present
******************************************************************************/
uint32_t CheckForPresentSettingsData(void)
{
 uint32_t Result[2];


 if ( u32IAP_BlankCheckSectors(SETTINGS_DATA_SECTOR, SETTINGS_DATA_SECTOR, Result) == IAP_STA_CMD_SUCCESS )
   return (0);
 else
   return (BLANK_CHECK_SECTOR_ERR);
}

//---------------------------------------------------------------------------//

/*****************************************************************************
Return rez if any errors
Return 0 if success.
******************************************************************************/
uint32_t  WriteBootModeOption(uint32_t BootMode)  
{
uint32_t AlignData[FLASH_BLOCK_SIZE / 4]; //буфер для 32 битного выравнивания данных для флэш 
uint32_t rez; //переменная для кода возврвата


 /*	Prepare Sectors to be flashed */
 rez = u32IAP_PrepareSectors(BOOT_MODE_SECTOR, BOOT_MODE_SECTOR);


if( rez != IAP_STA_CMD_SUCCESS) 
	return (PREPARE1_SECTOR_ERR+rez);

 rez = u32IAP_EraseSectors(BOOT_MODE_SECTOR, BOOT_MODE_SECTOR);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (ERASE_SECTOR_ERR+rez);

 /*	Prepare Sectors to be flashed */
 rez = u32IAP_PrepareSectors(BOOT_MODE_SECTOR, BOOT_MODE_SECTOR);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (PREPARE2_SECTOR_ERR+rez);

 memset((uint8_t *)AlignData, 0, FLASH_BLOCK_SIZE); //обнуляем буфер
 /*	Copy data (already) located in RAM to flash */
 memcpy((uint8_t *)AlignData, &BootMode, sizeof(BootMode) ); //копируем код бутлоадера

//сохраняем данныне
 rez = u32IAP_CopyRAMToFlash(BOOTMODE_FLASH_START, (uint32_t)AlignData, FLASH_BLOCK_SIZE);	
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (COPY_RAM_TO_FLASH_ERR+rez);

 /*	Verify the flash contents with the contents in RAM */
//проверяем данные
 rez = u32IAP_Compare(BOOTMODE_FLASH_START, (uint32_t)AlignData, FLASH_BLOCK_SIZE, 0);
 if( rez != IAP_STA_CMD_SUCCESS) 
	return (COMPARE_SECTOR_ERR+rez);

return rez;
}

/*****************************************************************************
******************************************************************************/
void   ReadBootModeOption(uint32_t *BootMode)  
{
//читаем режим работы
 memcpy(BootMode, (uint8_t *)(BOOTMODE_FLASH_START) , sizeof(uint32_t));
}


/*****************************************************************************
**                            End Of File
*****************************************************************************/

 

 

там еще есть хедеры, они просто константы описывают, надеюсь из названия констант будет понятно что они значат%). Поглядите, может вам поможет, может найдете какие отличия. У меня сколько не пробовал пишет прошивку и пользовательские данные без глюков. А в начале глюки были.

 

 

Share this post


Link to post
Share on other sites

Кстати, вы учли, что IAP использует немного вашей ОЗУ? Вот из даташита:

Flash programming commands use the top 32 bytes of on-chip RAM. The maximum stack usage in the user allocated stack space is 128 bytes, growing downwards.

Share this post


Link to post
Share on other sites
Кстати, вы учли, что IAP использует немного вашей ОЗУ? Вот из даташита:

Да, программа использует только первые 8кб ОЗУ

Share this post


Link to post
Share on other sites
А причина почему вызываю загрузчик из приложения, что бы уменьшить код загрузчика. В основном приложении гружу прошивку в SDRAM через USB, прыгаю на загрузчик, на всё готовое, инициализированное =). И просто копирую с SDRAM в буфер в RAMe, кусочками по 256 байт и пишу во флеш.

Правильная последовательность:

1. Загрузчик в начале флеш. Стартует первым. Проверяет валидность основной прошивки во флеш и наличие новой прошивки в SDRAM (инициализировав предварительно интерфейс SDRAM).

2. Если есть новая валидная прошивка в SDRAM - загрузчик шьёт её. В конце прошивки - сбрасывает флаг наличия новой прошивки.

3. Если имеется валидная прошивка во флеш (вновь прошита или имелась ранее), загрузчик передаёт управление на неё.

Основная программа, по завершении приёма новой прошивки в SDRAM, ставит флаг новой прошивки и делает аппаратный сброс CPU (сторожевиком или через спец.регистр).

Share this post


Link to post
Share on other sites
Правильная последовательность:

1. Загрузчик в начале флеш. Стартует первым. Проверяет валидность основной прошивки во флеш и наличие новой прошивки в SDRAM (инициализировав предварительно интерфейс SDRAM).

2. Если есть новая валидная прошивка в SDRAM - загрузчик шьёт её. В конце прошивки - сбрасывает флаг наличия новой прошивки.

3. Если имеется валидная прошивка во флеш (вновь прошита или имелась ранее), загрузчик передаёт управление на неё.

Основная программа, по завершении приёма новой прошивки в SDRAM, ставит флаг новой прошивки и делает аппаратный сброс CPU (сторожевиком или через спец.регистр).

Спасибо большое учту. Мысли примерно в этом же направлении и крутились..

Share this post


Link to post
Share on other sites

Вобшем код от Golikov A., не очень помог, все осталось также. Поробую с частотой процессора поиграть.

Share this post


Link to post
Share on other sites
Поробую с частотой процессора поиграть.
Угу. "Фигли думать, трясти надо". Что с ней играться, ее надо указать такой, как требует описание. И все. IAP уже давно используется во всех процессорах NXP и работает точно в соответствии с описанием. Надо искать причину. Делать это не видя вашего кода - невозможно (телепаты в отпуске). Ну выложу я вам свой код, он 100% рабочий. Подозреваю, что он точно так же не пойдет у вас - ведь этот код всего лишь обертка над вызовами IAP.

Вам писали о резервировании ОЗУ - а стек у вас случайно не на конец ОЗУ устанавливается?

 

#ifndef IAP_H__
#define IAP_H__
#include    <stdint.h>

class iap
{
public:
   // (NXP IAP) Status Codes
   enum status_t
   {
       CMD_SUCCESS,
       INVALID_CMD,
       SRC_ADDR_ERROR,
       DST_ADDR_ERROR,
       SRC_ADDR_NOT_MAPPED,
       DST_ADDR_NOT_MAPPED,
       COUNT_ERROR,
       INVALID_SECTOR,
       SECTOR_NOT_BLANK,
       SECTOR_NOT_PREPARED,
       COMPARE_ERROR,
       BUSY,
       PARAM_ERROR,
       ADDR_ERROR,
       ADDR_NOT_MAPPED,
       CMD_LOCKED,
       INVALID_CODE,
       INVALID_BAUD_RATE,
       INVALID_STOP_BIT,
       CODE_READ_PROT_ENABLED,
       MAX_ERROR
   };

   enum cmd_code_t
   {
       PREPARE = 50,
       COPY,
       ERASE,
       BLANK_CHECK,
       GET_PART_ID,
       GET_BOOT_VER,
       COMPARE,
       REINVOKE_ISP,
       READ_UID,
       SIZE_ALIGN = 0xFFFFFFFF
   };

   static uint_fast32_t const SECTOR_SIZE = 32 * 1024;
   static uint_fast32_t const MAX_SECTOR = 29;
   static uint_fast32_t const BLOCK_SIZE = 4096;

   static status_t check_blank(uint_fast8_t start_sector, uint_fast8_t end_sector);
   static status_t erase (uint_fast8_t start_sector, uint_fast8_t end_sector);
   static status_t erase (uint_fast8_t sector) { return erase (sector, sector); }

   static status_t write_block(uint32_t const *pDst, void const * pSrc);

private:
   struct command_t
   {
       cmd_code_t      Code;
       uint32_t        Param[4];
   };

   struct result_t
   {
       status_t        Status;
       uint32_t        Result[4];
   };

   static void (* const IAP)(command_t *params, result_t *result);

} static Flash __attribute__((unused));

#endif	// IAP_H__

#include    "iap.h"
#include    "../hardware.h"
#include    <macros.h>
#include    <scmRTOS.h>

void (* const iap::IAP)(command_t *params, result_t *result) = (void(*)(command_t *params, result_t *result))0x1fff1ff1;

iap::status_t iap::check_blank(uint_fast8_t start_sector, uint_fast8_t end_sector)
{
   iap::command_t   Command;
   iap::result_t    Result;

   Command.Code = BLANK_CHECK;
   Command.Param[0] = start_sector;
   Command.Param[1] = end_sector;

   TCritSect cs;
   IAP(&Command, &Result);

   return Result.Status;
}

iap::status_t iap::erase (uint_fast8_t start_sector, uint_fast8_t end_sector)
{
   if(check_blank(start_sector, end_sector) == CMD_SUCCESS)
       return CMD_SUCCESS;

   iap::command_t   Command;
   iap::result_t    Result;
   Command.Code = PREPARE;
   Command.Param[0] = start_sector;
   Command.Param[1] = end_sector;

   TCritSect cs;
   IAP(&Command, &Result);

   if (Result.Status == CMD_SUCCESS)
   {
       Command.Code = ERASE;
       Command.Param[0] = start_sector;
       Command.Param[1] = end_sector;
       Command.Param[2] = CCLK_FREQ / 1000;
       IAP(&Command, &Result);
       if (Result.Status == CMD_SUCCESS)
       {
           Command.Code = BLANK_CHECK;
           Command.Param[0] = start_sector;
           Command.Param[1] = end_sector;

           IAP(&Command, &Result);
       }
   }
   return Result.Status;
}

#include    <string.h>
iap::status_t iap::write_block(uint32_t const *pDst, void const * pSrc)
{
   uint32_t Buffer[bLOCK_SIZE / sizeof(uint32_t)];
   memcpy(Buffer, pSrc, sizeof(Buffer));

   iap::command_t   Command;
   iap::result_t    Result;

   Command.Code = PREPARE;
   Command.Param[0] = 1;               // do not overwrite bootloader
   Command.Param[1] = MAX_SECTOR;

   TCritSect cs;
   IAP(&Command, &Result);

   if (Result.Status != CMD_SUCCESS)
       return Result.Status;

   Command.Code = COPY;
   Command.Param[0] = (uint32_t) pDst;
   Command.Param[1] = (uint32_t) Buffer;
   Command.Param[2] = BLOCK_SIZE;
   Command.Param[3] = CCLK_FREQ / 1000;

   IAP(&Command, &Result);

   return Result.Status;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this