Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: как работать с IAP?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
cornflyer
Кто-нибудь научился работать с флеш-памятью LPC2148 через IAP?
Пока я лучше и проще выхода не нашел как поставить внешний i2c eeprom....
zltigo
Цитата(cornflyer @ Jan 28 2009, 17:26) *
Кто-нибудь научился работать...

 нашел как поставить внешний i2c eeprom....


A, что, кто-нибудь это (после чтения документации и многочисленных обсуждений на форуме ) не умеет smile.gif. А вообще смотря для чего, у меня I2C EEPROM почти всегда, не смотря на то, что и во FLASH многое что пишется (приложения, прошивки FPGA,.....).
cornflyer
на форуме нет внятного описания как работать с IAP, нет рабочего кода, только какие-то танцы с бубном smile.gif
пробовал код с форума - то пишет, то не пишет... непонятно почему
в самой документации на lpc2148 - только пару строк
хотя я все делал как требуется:
выключал прерывания
вызывал функцию подготовки флеша
потом писал туда массив байт из RAM'а
выложи свой рабочий код, который пишет и читает внутреннюю FLASH через IAP smile.gif
Nixon
Кроме документации существует еще и application note. Там и описание и код, все есть.
Сергей Борщ
Цитата(cornflyer @ Jan 29 2009, 14:47) *
выложи свой рабочий код, который пишет и читает внутреннюю FLASH через IAP smile.gif
Тут принято несколько иначе - вы выложите свой код, а мы покажем, что в нем не так. Уж для чтения-то зачем IAP???
cornflyer
да, я читал application note AN10256
компилятор Keil, target опция USE THUMB MODE включена....

CODE
/*
* IAP In-System Application Programming
*/

#include <LPC21xx.H>

// Clock Frequency
#define XTAL 12000000 // Oscillator Frequency

#ifdef BYPASS_IAP
#define CPUCLK XTAL // CPU Clock without PLL
#else
#define CPUCLK (XTAL*4) // CPU Clock with PLL
#endif

#define CCLK (XTAL / 1000) // CPU Clock without PLL in kHz

// Phase Locked Loop (PLL) definitions
#define PLL_BASE 0xE01FC080 // PLL Base Address
#define PLLCON_OFS 0x00 // PLL Control Offset
#define PLLSTAT_OFS 0x08 // PLL Status Offset
#define PLLFEED_OFS 0x0C // PLL Feed Offset
#define PLLCON_PLLE 0x01 // PLL Enable
#define PLLCON_PLLD 0x00 // PLL Disable
#define PLLCON_PLLC 0x03 // PLL Connect(0x02) | PLL Enable
#define PLLSTAT_PLOCK 0x0400 //1<<10 // PLL Lock Status


struct iap_in {
unsigned int cmd;
unsigned int par[4];
};

typedef void (*IAP)(struct iap_in *in, unsigned int *result);
#define iap_entry ((IAP) 0x7FFFFFF1) // IAP entry point


/* Default Interrupt Function: may be called when interrupts are disabled */
void def_isr (void) __irq {
;
}


#ifdef BYPASS_IAP
/*
* Switch CPU to PLL clock
*/
void start_pll (void) {
__asm {
LDR R0, =PLL_BASE
MOV R1, #0xAA
MOV R2, #0x55

// Enable PLL
MOV R3, #PLLCON_PLLE
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]

// Wait until PLL Locked
LDR R2, =PLLSTAT_PLOCK
PLL_Loop:
LDR R3, [R0, #PLLSTAT_OFS]
CMP R3, R2
BEQ PLL_Loop

// Switch to PLL Clock
MOV R2, #0x55
MOV R3, #PLLCON_PLLC
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
}
}


/*
* Switch CPU to standard XTAL
*/
void stop_pll(void) __arm {
__asm {
LDR R0, =PLL_BASE
MOV R1, #0xAA
MOV R2, #0x55

// Disable PLL
MOV R3, #PLLCON_PLLD
STR R3, [R0, #PLLCON_OFS]
STR R1, [R0, #PLLFEED_OFS]
STR R2, [R0, #PLLFEED_OFS]
}
}

#endif

/*
* Convert 'addr' to sector number
*/
unsigned int get_secnum (void *addr) {
unsigned int n;

n = ((unsigned int) addr >> 13) & 0x1F; // pseudo sector number

if (n >= (0x30000 >> 13)) {
n -= 14; // high small 8kB Sectors (
}
else if (n >= (0x10000 >> 13)) {
n = 7 + (n >> 3); // large 64kB Sectors
}
return (n); // sector number
}


/*
* Erase Sector between 'start' and 'end'
* Return: IAP error code (0 when OK)
* NOTES: start needs to be a 256 byte boundary
* size should be 256, 512, 1024 or 4089
*/
unsigned int erase (void* start, void* end) {
struct iap_in iap; // IAP input parameters
unsigned int result[16]; // IAP results
unsigned int save_VicInt; // for saving of interrupt enable register

save_VicInt = VICIntEnable; // save interrupt enable status
VICIntEnClr = 0xFFFFFFFF; // disable all interrupts

#ifdef BYPASS_IAP
stop_pll(); // IAP requires to run without PLL
#endif

iap.cmd = 50; // IAP Command: Prepare Sectors for Write
iap.par[0] = get_secnum (start); // start sector
iap.par[1] = get_secnum (end); // end sector
iap_entry (&iap, result); // call IAP function
if (result[0]) goto exit; // an error occured?

iap.cmd = 52; // IAP command: Erase Flash
iap.par[0] = get_secnum (start); // start sector
iap.par[1] = get_secnum (end); // end sector
iap.par[2] = CCLK; // CPU clock
iap_entry (&iap, result); // call IAP function

exit:

#ifdef BYPASS_IAP
start_pll(); // start PLL
#endif

VICIntEnable = save_VicInt; // enable interrupts
return (result[0]);
}


/*
* Program *data to flash_addr. number of bytes specified by size
* Return: IAP error code (0 when OK)
* Note:
*/
unsigned int program (void *flash_addr, void *data, unsigned int size) {
struct iap_in iap; // IAP input parameters
unsigned int result[16]; // IAP results
unsigned int save_VicInt; // for saving of interrupt enable register

save_VicInt = VICIntEnable; // save interrupt enable status
VICIntEnClr = 0xFFFFFFFF; // disable all interrupts

#ifdef BYPASS_IAP
stop_pll(); // IAP requires to run without PLL
#endif

iap.cmd = 50; // IAP Command: Prepare Sectors for Write
iap.par[0] = get_secnum (flash_addr); // start sector
iap.par[1] = iap.par[0]; // end Sektor
iap_entry (&iap, result); // call IAP function
if (result[0]) goto exit; // an error occured?

iap.cmd = 51; // IAP Command: Copy RAM to Flash
iap.par[0] = (unsigned int) flash_addr; // destination-addr
iap.par[1] = (unsigned int) data; // source-addr
iap.par[2] = size; // number of bytes
iap.par[3] = CCLK; // CPU clock
iap_entry (&iap, result); // call IAP function

exit:

#ifdef BYPASS_IAP
start_pll(); // start PLL
#endif

VICIntEnable = save_VicInt; // enable interrupts
return (result[0]);
}



unsigned char vals[512];


void main (void) {
unsigned int i;

unsigned int volatile start;

for (start = 0; start < 1000000; start++) {
; // wait for debugger connection (about 0.3 sec)
}

VICDefVectAddr = (unsigned int) def_isr; // for spurious interrupts

for (i = 0; i < sizeof (vals); i++) {
vals[i] = (unsigned char) i;
}

program (0x30000, vals, sizeof (vals));
program (0x31000, vals, sizeof (vals));
program (0x32000, vals, sizeof (vals));
erase (0x30000, 0x31FFF);
erase (0x32000, 0x33FFF);

while (1);
}


zltigo
Цитата(cornflyer @ Jan 29 2009, 15:47) *
на форуме нет внятного описания как работать с IAP, нет рабочего кода, только какие-то танцы с бубном smile.gif



Никаких танцев при шатном использовании.

Цитата
..непонятно почему


На вопрос "почему" отвечает сам IAP возвращая коды ошибок, только вот Вы их анализировать не считаете нужным sad.gif. Начните с этого

Цитата
в самой документации на lpc2148 - только пару строк


Вообще-то там целый раздел...
segment
Кстати да, интересная тема. Может ктонибудь объяснит или напишет небольшой РАБОЧИЙ, самое главное РАБОЧИЙ, код для работы с flash.
А так же интересует вопрос - как чтолибо сохранить во flash, то есть как определяем свободные диапазоны адресов? и что они не будут заняты в будущем?

Просто мысль была сохранять данные, чтобы при выключении они сохранялись. В АВРках было проще, там почти везде был еепром
Сергей Борщ
Цитата(Сега @ Jan 31 2009, 18:32) *
то есть как определяем свободные диапазоны адресов? и что они не будут заняты в будущем?
Резервируем нужную область в скрипте линкера. Он будет ругаться, если в будущем будет попытка ее занять чем-то другим.
cornflyer
внутренний flash стоит использовать для хранения редкоменяющейся инфы...
часто писать во внутренний flash - плохой стиль
у него ресурс всего 100000 циклов записи....
запись через IAP занимает время, причем проц не обрабатывает прерывания....
если 100 раз в сутки приходица сохранять инфу - лучше писать во внешний eeprom
у него ресурс 1000000 циклов
вот например можно поставить i2c eeprom M24C64
код для чтения/записи приведен ниже:
Код
#include "lpc214x.h"
/*-------------------------------------------------------------------------*/
#define SDA_BIT    (1<<3)//for olimex board
#define SCL_BIT    (1<<2)//for olimex board
#define I2C_ADDR (0x50)//I2C Slave Address
/*-------------------------------------------------------------------------*/
void I2C_DELAY(void){
    volatile z=1000;
    while(z) z--;
}
/*-------------------------------------------------------------------------*/
unsigned char I2C_SDA(void){
    return (IOPIN0&SDA_BIT);    
}
/*-------------------------------------------------------------------------*/
void I2C_SDA_HIGH(void){
    IODIR0 &=~ SDA_BIT;//input    
}
/* -------------------------------------------------------------------------*/
void I2C_SDA_LOW(void){
    IOCLR0 = SDA_BIT;
    IODIR0 |= SDA_BIT;//output low
}
/*-------------------------------------------------------------------------*/
void I2C_SCL_HIGH(void){
    IODIR0 &=~ SCL_BIT;//input
}
/*-------------------------------------------------------------------------*/
void I2C_SCL_LOW(void){
    IOCLR0 = SCL_BIT;
    IODIR0 |= SCL_BIT;//output low
}
/*-------------------------------------------------------------------------*/
unsigned char i2c_send_byte(unsigned char b){
    unsigned char result = 0;
    unsigned int i = 0;
    for(i=0;i<8;i++){
        //Set Data
        if(b&0x80){// == 1000 0000
            I2C_SDA_HIGH();
        }else{
            I2C_SDA_LOW();
        }
        b = b<<1;//shift left by one position
        I2C_DELAY();
        I2C_SCL_HIGH();//make clock pulse
        I2C_DELAY();
        I2C_SCL_LOW();
        I2C_DELAY();    
    }
    //Acknowledge
    I2C_SDA_HIGH();
    I2C_DELAY();
    I2C_SCL_HIGH();//make clock pulse
    I2C_DELAY();
    if(I2C_SDA()){//check i2c slave acknowledge
        result = 1;
    }else{
        result = 0;
    }
    I2C_SCL_LOW();
    I2C_DELAY();
    return result;
}
/*-------------------------------------------------------------------------*/
unsigned char i2c_write(unsigned int addr,unsigned char b){
    unsigned char result = 0;
    //Initial state (stop condition)
    I2C_SCL_HIGH();
    I2C_DELAY();
    I2C_SDA_HIGH();
    I2C_DELAY();
    //Start (start condition)
    I2C_SDA_LOW();
    I2C_DELAY();
    I2C_SCL_LOW();
    I2C_DELAY();
    //Send i2c address
    if(i2c_send_byte(I2C_ADDR<<1)){//RW=0
        result = 1;
    }else{
        if(i2c_send_byte(addr>>8))result = 1;//high addr
        if(i2c_send_byte(addr))result = 1;//low addr
        if(i2c_send_byte(b))result = 1;
    }
    //Stop (stop condition)
    I2C_SDA_LOW();
    I2C_DELAY();
    I2C_SCL_HIGH();
    I2C_DELAY();
    I2C_SDA_HIGH();
    I2C_DELAY();
    return result;
}
/*-------------------------------------------------------------------------*/
void i2c_write_byte(unsigned int addr, unsigned char b){
    unsigned char result = 1;
    while(result)result = i2c_write(addr,b);
}
/*-------------------------------------------------------------------------*/
void i2c_read_page(unsigned int addr, unsigned char *page_buff, unsigned int page_length){
    unsigned char data_byte = 0;
    int b;
    //Initial state
    I2C_SCL_HIGH();
    I2C_DELAY();
    I2C_SDA_HIGH();
    I2C_DELAY();
    //Start (start condition)
    I2C_SDA_LOW();
    I2C_DELAY();
    I2C_SCL_LOW();
    I2C_DELAY();
    //Send address
    i2c_send_byte(I2C_ADDR<<1);//RW=0
    i2c_send_byte(addr>>8);//high addr
    i2c_send_byte(addr);//low addr
    //Start (start condition)
    I2C_SCL_HIGH();
    I2C_DELAY();
    I2C_SDA_LOW();
    I2C_DELAY();
    I2C_SCL_LOW();
    I2C_DELAY();
    i2c_send_byte((I2C_ADDR<<1)|0x01);//RW = 1
    while(page_length){//read page    
        I2C_SDA_HIGH();
        for(b=8;b--;){
            I2C_DELAY;
            I2C_SCL_HIGH();
            I2C_DELAY();
            data_byte = (data_byte<<1)|((I2C_SDA())?0x01:0x00);
            I2C_DELAY();
            I2C_SCL_LOW();
            I2C_DELAY();
        }
        *page_buff = data_byte;
        page_buff++;
        data_byte = 0;
        page_length--;
        //Acknowledge
        if(page_length) I2C_SDA_LOW(); else I2C_SDA_HIGH();
        I2C_DELAY();
        I2C_SCL_HIGH();
        I2C_DELAY();
        I2C_DELAY();
        I2C_SCL_LOW();
        I2C_DELAY();
    }
    //Stop (stop condition)
    I2C_SDA_LOW();
    I2C_DELAY();
    I2C_SCL_HIGH();
    I2C_DELAY();
    I2C_SDA_HIGH();
    I2C_DELAY();
}
Qwertty
Цитата(cornflyer @ Feb 2 2009, 10:21) *
вот например можно поставить i2c eeprom M24C64
код для чтения/записи приведен ниже:

А почему софтовый I2C???
yuri_t
По поводу IAP можно посмотреть здесь:

http://www.tnkernel.com/usb_fw_upgrader.html
(usb-fwu-1-0-1-lpc214x.zip -> fwu_asm.s)

По поводу I2C - здесь:
cornflyer
преимущества софтового i2c :
- софтовый i2c меньше занимает, работает без глюков wink.gif (смотри еррату на lpc2148)
- SDA и SCL можно на любые ноги повесить

мой личный опыт показывает что код, написанный на все случаи жизни - работает медленно, глючит и
много жрет ресурсов....
поэтому я стараюсь кодить только то, что нужно для решения поставленной задачи
zltigo
Цитата(cornflyer @ Feb 2 2009, 14:17) *
софтовый i2c меньше занимает, работает без глюков wink.gif (смотри еррату на lpc2148)



Смотреть нечего - уже ДЕСЯТКИ лет I2C на любых Филипсовских контролерах никаких errata и глюков не имеет, является отлитым в бронзе стандартом. И, как Вам показалось, заработавший copy-paste  из интернету софтового I2C не повод изрекать глупости про "глюки", "ресурсы" и "медленность".

 
cornflyer
согласен.
перечитал еррату - действительно с i2с в lpc2148 проблем нет. похоже я перепутал с другим камнем.
i2c контроллер нужен если на шине много устройств
а если всего один eeprom и к тому же накосячил с разводкой - тут поможет только софтверный i2c.
скоро буду разводить новую плату под ecos - вот тут мне понадовица i2c контроллер

P.S. кстати, нашел в ecos'е пару багов - неправильно было определено адресное смещение - должно быть 0x10000000
из-за этого код больше 1Mb не работал...
и еще там не включена опция кэширования.....
в итоге после фиксов все заработало в 10 раз (!!!!) быстрее!
bigarmer
CODE


===========IAP.C=============



#include "IAP.h"

#define IAP_CLK Fcclk

#define IAP_LOCATION 0x7FFFFFF1
#define iap_entry(a, cool.gif ((void (*)())(IAP_LOCATION))(a, cool.gif

unsigned long command[5] = {0,0,0,0,0};
unsigned long result[3]= {0,0,0};


/*************************************************************************
* Function Name: IAP_PrepareSec
* Parameters: unsigned long StartSecNum -- Start Sector Number
* unsigned long EndSecNum -- End Sector Number
* Return: unsigned long -- Status Code
*
* Description: This command must be executed before executing "Copy RAM to Flash" or
* "Erase Sector(s)" command.
*
*************************************************************************/
unsigned long IAP_PrepareSec (unsigned long StartSecNum, unsigned long EndSecNum)
{
if (EndSecNum < StartSecNum)
return IAP_STA_INVALD_PARAM;

command[0] = IAP_CMD_PrepareSec;
command[1] = StartSecNum;
command[2] = EndSecNum;
iap_entry(command, result);

return result[0];
}

/*************************************************************************
* Function Name: IAP_CopyRAMToFlash
* Parameters: unsigned long dst -- Destination Flash address, should be a 256 byte boundary.
* unsigned long src -- Source RAM address, should be a word boundary
* unsigned long number -- 256 | 512 |1024 |4096
* Return: unsigned long -- Status Code
*
* Description: This command is used to program the flash memory.
*
*************************************************************************/
unsigned long IAP_CopyRAMToFlash (unsigned long dst, unsigned long src,
unsigned long number)
{
command[0] = IAP_CMD_CopyRAMToFlash;
command[1] = dst;
command[2] = src;
command[3] = number;
command[4] = IAP_CLK / 1000; // Fcclk in KHz
iap_entry(command, result);

return result[0];
}


/*************************************************************************
* Function Name: IAP_EraseSec
* Parameters: unsigned long StartSecNum -- Start Sector Number
* unsigned long EndSecNum -- End Sector Number
* Return: unsigned long -- Status Code
*
* Description: This command is used to erase a sector or multiple sectors of on-chip Flash
* memory.
*
*************************************************************************/
unsigned long IAP_EraseSec (unsigned long StartSecNum, unsigned long EndSecNum)
{
if (EndSecNum < StartSecNum)
return IAP_STA_INVALD_PARAM;

command[0] = IAP_CMD_EraseSec;
command[1] = StartSecNum;
command[2] = EndSecNum;
command[3] = IAP_CLK / 1000;
iap_entry(command, result);

return result[0];
}

/*************************************************************************
* Function Name: IAP_BlankChkSec
* Parameters: unsigned long StartSecNum -- Start Sector Number
* unsigned long EndSecNum -- End Sector Number
* Return: unsigned long -- Status Code
*
* Description: This command is used to blank check a sector or mutilple sectors of on-chip
* Flash memory.
*
*************************************************************************/
unsigned long IAP_BlankChkSec (unsigned long StartSecNum, unsigned long EndSecNum,
unsigned long * pResult)
{
if (EndSecNum < StartSecNum)
return IAP_STA_INVALD_PARAM;

command[0] = IAP_CMD_BlankChkSec;
command[1] = StartSecNum;
command[2] = EndSecNum;

iap_entry(command, result);

if (result[0] == IAP_STA_SECTOR_NOT_BLANK)
{
*pResult = result[0];
*(pResult+1) = result[1];
}

return result[0];
}

/*************************************************************************
* Function Name: IAP_ReadParID
* Parameters: unsigned long * PartID
* Return: unsigned long -- Status Code
*
* Description: This command is used to read the part identification number.
*
*************************************************************************/
unsigned long IAP_ReadParID (unsigned long * PartID)
{

command[0] = IAP_CMD_ReadParID;
iap_entry(command, result);
*PartID = result[1];

return result[0];
}

/*************************************************************************
* Function Name: IAP_ReadBootVer
* Parameters: char * MajorVer
* char * MinorVer
* Return: unsigned long -- Status Code
*
* Description: This command is used to read the boot code version number.
*
*************************************************************************/
unsigned long IAP_ReadBootVer (unsigned long * MajorVer, unsigned long * MinorVer)
{
command[0] = IAP_CMD_ReadBootVer;
iap_entry(command, result);
*MajorVer = (result[1] & 0xff00)>>8;
*MinorVer = result[1] & 0xff;

return result[0];
}

/*************************************************************************
* Function Name: IAP_Compare
* Parameters: unsigned long dst -- Destination Flash address
* unsigned long src -- Source RAM address
* unsigned long number -- Should be in mutilple of 4
* Return: unsigned long -- Status Code
*
* Description: This command is used to compary the memory contents at two locations.
*
* NOTE: Compary result may not be correct when source or destination address contains
* any of the first 64 bytes starting from address zero. First 64 bytes can be re-mapped
* to RAM.
*
*************************************************************************/
unsigned long IAP_Compare (unsigned long dst, unsigned long src,
unsigned long number, unsigned long *offset)
{
command[0] = IAP_CMD_Compare;
command[1] = dst;
command[2] = src;
command[3] = number;
iap_entry(command, result);

if (result[0] == IAP_STA_COMPARE_ERROR)
*offset = result[1];

return result[0];
}

void IAP_ReinvokeISP(void)
{
command[0] = IAP_CMD_REINVOKEISP;
iap_entry(command, result);;
}

=====================================
===========IAP.H=============
#ifndef __IAP_H
#define __IAP_H

/* IAP Command */
#define IAP_CMD_PrepareSec 50 //select sector
#define IAP_CMD_CopyRAMToFlash 51 //copy data from ram to flash
#define IAP_CMD_EraseSec 52 //erase sector
#define IAP_CMD_BlankChkSec 53 //check if sector is blank
#define IAP_CMD_ReadParID 54 //read chip ID
#define IAP_CMD_ReadBootVer 55 //read BOOT version
#define IAP_CMD_Compare 56 //compare
#define IAP_CMD_REINVOKEISP 57 //reinvoke ISP command

/* IAP Status Codes */
#define IAP_STA_CMD_SUCCESS 0
#define IAP_STA_INVALID_COMMAND 1
#define IAP_STA_SRC_ADDR_ERROR 2
#define IAP_STA_DST_ADDR_ERROR 3
#define IAP_STA_SRC_ADDR_NOT_MAPPED 4
#define IAP_STA_DST_ADDR_NOT_MAPPED 5
#define IAP_STA_COUNT_ERROR 6
#define IAP_STA_INVALID_SECTOR 7
#define IAP_STA_SECTOR_NOT_BLANK 8
#define IAP_STA_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9
#define IAP_STA_COMPARE_ERROR 10
#define IAP_STA_BUSY 11

#define IAP_STA_INVALD_PARAM 12

extern unsigned long IAP_PrepareSec (unsigned long, unsigned long);
extern unsigned long IAP_CopyRAMToFlash (unsigned long dst, unsigned long src,
unsigned long number);
extern unsigned long IAP_EraseSec (unsigned long StartSecNum, unsigned long EndSecNum);
extern unsigned long IAP_BlankChkSec (unsigned long StartSecNum, unsigned long EndSecNum,
unsigned long * pResult);
extern unsigned long IAP_ReadParID (unsigned long * PartID);
extern unsigned long IAP_ReadBootVer (unsigned long * MajorVer, unsigned long * MinorVer);
extern unsigned long IAP_Compare (unsigned long dst, unsigned long src,
unsigned long number, unsigned long *offset);
extern void IAP_ReinvokeISP(void);


#endif

TanT
Позвольте задать вопрос в этой теме касаемо IAP. В мануале на LPC2378, который использую, написанно чёрным по-нерусски: "Up to 512 kB on-chip Flash Program Memory with In-System Programming (ISP) and In-Application Programming (IAP) capabilities. Single Flash sector or full-chip erase in 400 ms and 256 bytes programming in 1 ms". То есть для стирания !одного! или !всех! секторов без разницы надо 400 мс, а для записи 4кб=256*16=16мс? а сколько надо для подготовки сектора к записи и стиранию, и сравнения двух секторов? по этим операциям временных рамок не нашёл.
zltigo
Цитата(TanT @ Feb 18 2009, 15:27) *
а сколько надо для подготовки сектора к записи и стиранию
D
В миллисекундном измерении приблизительно "нисколько".
Цитата
, и сравнения двух секторов?

А это вообще бесполезность - сами можете сравнить - за сколько сравните, за столько и будет.
TanT
Я так и думал smile.gif . А касаемо стирания одного сектора? "Single Flash sector or full-chip erase in 400 ms "
И вообще имеет смысл каждый раз чистить сектор перед употреблением? То есть, не правильно выразился, какова вероятность ошибочной записи сектора без его предворительного стирания?
MrYuran
Цитата(TanT @ Feb 19 2009, 08:49) *
И вообще имеет смысл каждый раз чистить сектор перед употреблением? То есть, не правильно выразился, какова вероятность ошибочной записи сектора без его предворительного стирания?

Такя же, как и вероятность записи единицы на место записанного ранее нуля. То есть, не так выразился, записать можно только ноль на месте единицы, для обратной записи нужно стирание
TanT
Цитата
(TanT @ Feb 19 2009, 08:49)
И вообще имеет смысл каждый раз чистить сектор перед употреблением? То есть, не правильно выразился, какова вероятность ошибочной записи сектора без его предворительного стирания?

Глупый вопрос, blush.gif Следующий раз буду внимательнее слушать старших товарищей.

Однако, всё таки кто-нибудь сможет ответить на вопрос: сколько требуется времени для стирания одного сектора по IAP для LPC2378?
MikePic
TanT
Цитата
Однако, всё таки кто-нибудь сможет ответить на вопрос: сколько требуется времени для стирания одного сектора по IAP для LPC2378?

А просто взять и измерить?
1. Таймером - считать значение до входа в процедуру стирания, считать значение после выхода, вывести в UART разницу
2. Осциллом - установить пин из 0 в 1 до входа, из 1 в 0 после выхода
zltigo
Цитата(MikePic @ Feb 19 2009, 10:11) *
А просто взять и измерить?

Зачем? Получить некое конкретное зачение для данного чипа в данный момент времени? Что будет у другого экземпляра? Что будет после 1000 стираний? Производитель документирует 400 - их и нужно придерживаться.
TanT
Цитата
Производитель документирует 400 - их и нужно придерживаться.


Игорь, простите, конечно, настырность, но эти милисекунды очень критичны. Развейте наконец мои сомнения. Сколько времени требуется для стирания одного сектора? А десяти?
zltigo
Цитата(TanT @ Feb 19 2009, 13:04) *
Сколько времени требуется для стирания одного сектора? А десяти?

Столько, сколько Вы прочитали в документации - любое стирание хоть чипа, хоть одного сектора 400ms. Десять секторов последовательно - в десять раз больше одного сектора. Любые надежды на ускорение и из последствия на Вашей совести. Когда-то давно давно еще на LPC2114 измерения делал - результаты где-то в глубинах форума должны быть. Время стирания помнится много меньше 400ms ну и что? Хотите занятся радиолюбительством? - Измеряйте и занимайтесь sad.gif
TanT
Спасибо большое, именно это хотел услышать.
А радиолюбительством я вроде и не собирался заниматься, не тот случай. wink.gif
HARMHARM
Если уж хочется что-то поделать пока идет стирание, можно разместить функцию в RAM. Если нужны прерывания - мапировать векторы в RAM и разместить в RAM обработчики. У меня так сбрасывается внешний вочдог пока идет стирание.
Denisvak
Позвольте задать вопрос в этой же теме дабы не создавать новой.
Собираюсь писать свой загрузчик под LPC21хх через модуль IAP.
Состоит из программы ПК и программы для контроллер. ПО на ПК будет принимать прошивку в в виде hex файла и отправлять контроллеру через хх интерфейс, допусти 232. Надо ли мне как-то преобразовывать в другой формат прежде чем писать прошивку во флеш, или хватит просто класть по нужным адресам?

Ещё вопрос по созданию проектов в IAR
Бутлодер должен висеть в самом начале флеша(первые 4кб), и запускаться первым затем передавать управление основной программе функцией ((void (*)())0x1000)();
Основная программа расположена с адреса 0x1000. Как в данном случае должна происходить работа прерываний для этих разный областей.
etoja
Прилагаю подробную инструкцию по IAP для использования с компилятором Crossworks.
Извиняюсь перед автором этого документа, что не записал его адрес в интернете.
Denisvak
Цитата(etoja @ Feb 24 2009, 18:18) *
Прилагаю подробную инструкцию по IAP для использования с компилятором Crossworks.
Извиняюсь перед автором этого документа, что не записал его адрес в интернете.

Спасибо за пример, разбираюсь smile.gif

Вопрос по прерываниям в основной программой. Если я линкеру укажу файлик "LPC2148_flash.xcl" в котором ручками поправлю начало флеш
Код
-DROMSTART=00001000
вместо
Код
-DROMSTART=00000040
и прерывания
Код
-Z(CODE)INTVEC=00001000-0000103f
вместо
Код
-Z(CODE)INTVEC=00000000-0000003f
будут ли корректно работать прерывания? Камешек lpc2148
Всем спасибо.
Сергей Борщ
Цитата(Denisvak @ Feb 24 2009, 18:26) *
будут ли корректно работать прерывания?
При возникновении исключения процессор переходит на адреса 0-0x3f. Куда вы положите вектора - ему все равно. Он будет переходить по заложенным в него железно адресам 0...0x3f. Один из возможных вариантов решения вашей проблемы - remap. Читайте про него в документации на ARM7 и ищите по форуму.
TanT
Вопрос в продолжении темы IAP: команда 56 - сравнение секторов. насколько быстро и надёжно всё это происходит, например, для сектора в 4кб? Вообще, в принципе какая вероятность записать с ошибкой сектор по IAP?
etoja
Цитата(TanT @ Feb 26 2009, 08:05) *
Вопрос в продолжении темы IAP: команда 56 - сравнение секторов. насколько быстро и надёжно всё это происходит, например, для сектора в 4кб? Вообще, в принципе какая вероятность записать с ошибкой сектор по IAP?


Записывайте в конец сектора свою 32-битную контрольную сумму.
TanT
Если сравнение гарантирует 100% выявление ошибок, то за чем лишнии действия? Однако, кто ответит что быстрее и надёжнее - вычисление 32-битной(16-битной) контрольной суммы или стандартная операция сравнения IAP?
KRS
Цитата(TanT @ Feb 26 2009, 10:52) *
Если сравнение гарантирует 100% выявление ошибок, то за чем лишнии действия? Однако, кто ответит что быстрее и надёжнее - вычисление 32-битной(16-битной) контрольной суммы или стандартная операция сравнения IAP?

а у IAP есть операция сравнения? Сравнивать надо самим, благо весь флеш доступен на чтение.
Контрольную сумму вычислять вообще смысла нет! Потому что все равно надо будет считывать все данные, чем производить с ними операции проще сравнить с оригиналом. Да и скорость обработки данных не сопоставима со скоростью их передачи для прошивки и временем прошивки.
etoja
Контрольная сумма нужна обязательно, поскольку в момент программирования может выключиться питание прибора.
Но это - для профессионального оборудования.
Denisvak
Цитата(TanT @ Feb 26 2009, 10:52) *
Если сравнение гарантирует 100% выявление ошибок, то за чем лишнии действия? Однако, кто ответит что быстрее и надёжнее - вычисление 32-битной(16-битной) контрольной суммы или стандартная операция сравнения IAP?


Какая-то у вас тяга к быстрым вычислениям smile.gif Для чего?
TanT
Цитата
Контрольная сумма нужна обязательно, поскольку в момент программирования может выключиться питание прибора.
Но это - для профессионального оборудования.

контрольная сумма будет обязательно будет, точнее она есть (16). И данные будут записываться уже достоверные, то есть требуется сличить записанные и записываемые данные. Совет KRS я считаю правильным и не пременно им воспользуюсь. Уцепился сразу за эту команду сравнения IAP, казалось что специально написанная функция должна быть оптимизированна и прочее smile.gif

Цитата
Какая-то у вас тяга к быстрым вычислениям Для чего?

Кроме записи по IAP много чего ещё должно работать, и запись далеко не приоритетная задача, и чем меньше времени она будет крутиться тем лучше. Вообще запись данных требуется проводить не заметно для остальных процессов, что сильно затрудняет обязательное требование запрета прерываний. Поэтому и стараюсь точно определить все временные рамки и по возможности их минимизировать, в частности на проверку данных. Большие трудности создаёт возможность неудачной записи (вероятность ошибки, думаю, никому неизвестна) 400 мс для стирания и повторной записи у меня нет.
etoja
Цитата(TanT @ Mar 2 2009, 09:16) *
Большие трудности создаёт возможность неудачной записи (вероятность ошибки, думаю, никому неизвестна) 400 мс для стирания и повторной записи у меня нет.


Неудачная запись по вине процессора никогда не встречалась.
По вине пропадания питания в момент записи - возможна.
Запись во внутреннюю память процессора - монопольный процесс. Если это не устраивает - используйте внешнюю FRAM.
HARMHARM
Цитата(TanT @ Mar 2 2009, 08:16) *
Вообще запись данных требуется проводить не заметно для остальных процессов, что сильно затрудняет обязательное требование запрета прерываний.

Запрет прерываний - требование не обязательное. Обязательное требование - отсутствие доступа к Flash. Прерывания могут спокойно работать в RAM.
Цитата
The on-chip flash memory is not accessible during erase/write operations. When the user
application code starts executing the interrupt vectors from the user flash area are active.
The user should either disable interrupts, or ensure that user interrupt vectors are active in
RAM and that the interrupt handlers reside in RAM, before making a flash erase/write IAP
call. The IAP code does not use or disable interrupts.
TanT
Цитата
Запрет прерываний - требование не обязательное. Обязательное требование - отсутствие доступа к Flash. Прерывания могут спокойно работать в RAM.
угу, читал. для меня обязательное unsure.gif
Denisvak
Сергей Борщ и etoja
Спасибо Вам за помощь все работает smile.gif
vesago
Прошу совета по сабжу. Я использую LPC2214. C 0 по 0x1FFF расположен загрузчик, с 0x2000 приложение. Все работате отлично. Решил я написать приложение, которое будет обновлять загрузчик. То есть образ нового загрузчика расположен по адресу 0x6000. После заливки, это приложение через IAP должно стереть сектор где расположен старый загрузчик, т.е. сектор 0 и скопировать туда образ нового загрузчика с адреса 0x6000. При отладке я пробовал копировать в область с адресом 0x8000 - проблем не было. В боевом варианте после стирания сектора 0 система зависает. Если посмотреть память флэш меджиком, видно что сектор 0 стерт. Почему система отваливается, ума не приложу. Вроде все сконфигурировано правильно - в опциях кейла и стартапе задал, что прошивка начинается с адреса 0x2000. Может есть какие-то особенности IAP - типа клинит соседний сектор? JTAG смотрел - показалось, что коллапс наступает после восстановления прерываний.
GetSmart
Ну дык если стёрли нулевой сектор, то стёрли и вектора прерываний по адресам 00-3f. Либо делайте ремап на ОЗУ (заполнив вектора 0x40000000-0x4000001f) и уже потом разрешайте прерывания, либо не разрешайте прерывания вообще до окончательной перезаписи нулевого сектора.
vesago
Я думал, что если начало прошивки сконфигурировано с адреса 0x2000, то и вектора там же. А как же она работает в обычном режиме? Там же сидит загрузчик как отдельное приложение. Получается для ремапа, мне нужно в начало рамы копирнуть область векторов с 0 флеши и задать ремап?
HARMHARM
Цитата(vesago @ Mar 15 2009, 20:10) *
Я думал, что если начало прошивки сконфигурировано с адреса 0x2000, то и вектора там же. А как же она работает в обычном режиме? Там же сидит загрузчик как отдельное приложение. Получается для ремапа, мне нужно в начало рамы копирнуть область векторов с 0 флеши и задать ремап?

Да, этого достаточно.
GetSmart
Цитата(vesago @ Mar 15 2009, 23:10) *
А как же она работает в обычном режиме? Там же сидит загрузчик как отдельное приложение.

В векторах программ чаще всего используется IRQ. Если по адресу 0x18 в нулевом секторе (загрузчике) стоит команда LDR PC,[PC,#-0xFF0], то этого достаточно чтобы IRQ прикладной программы нормально действовали. Для FIQ тоже можно сделать похожим образом. Ну а остальные вестора исключительных ситуаций обычно не возникают и для большинства программ не имеют значения. Обычно там вообще стоят заглушки типа зависона.
vesago
Спасибо, все понятно.
ar__systems
Цитата(cornflyer @ Jan 29 2009, 07:47) *
на форуме нет внятного описания как работать с IAP, нет рабочего кода, только какие-то танцы с бубном smile.gif
пробовал код с форума - то пишет, то не пишет... непонятно почему
в самой документации на lpc2148 - только пару строк
хотя я все делал как требуется:
выключал прерывания
вызывал функцию подготовки флеша
потом писал туда массив байт из RAM'а
выложи свой рабочий код, который пишет и читает внутреннюю FLASH через IAP smile.gif

Может вы не ту доку читали? Я пользовался LPC2478, в доке все внятно прописано более менее. Не пара строк. За пару часов запись удалось осуществить.
TanT
Вопрос к etoja по поводу записи, точнее верификации.
Пишу себе спокойно по IAP, проверяю двумя способами: в лоб по рекомендации KRS и IAPовским сравнением. И нет такого момента, чтобы без ошибок обошлось на 32 кб записи 2-3 ошибки в среднем. Ну это ещё полбеды. Смотрю где ошибка - записанно всё что требуется (покрайней мере в том месте куда указывают функции сравнения). Ладно, думаю, по не опытности накосячил где-нить с указателями и не то сравниваю, однако, прошивка не запускается. Но стоит повторить целиком запись прошивки "поверх" старой, и - о чудо - всё работает и ошибок проверки не возникает. Чем это может быть обоснованно? Как всё таки достоверно сравнивать данные из ОЗУ и флеш?

P.S. Записывал массив одинаковых символов, смотрел глазками что вышло, всё в идеале, хотя ошибки всё равно лезут.
Прерывания естественно все отключены, даже пробовал модуль акселератора памяти отключать (МАМ), думалось может при обращении к флеш не-то читается - не помогло в общем.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.