Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Программная запись FLASH AT91SAM7S128
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
MiklPolikov
at89sam7s128

Нужно сохранять данные при отключении питания.

Через указатель на Internal Flash (адреса с с 0x00100000 по 0x0020000) получается только читать.

сhar *pnr;
pnr= (char*) 0x00100001;
*pnr=0x33;

Этот код выполняется но во FLASH ничего не записывается.

Как записать во FLASH ?


Спасибо !
aaarrr
Цитата(MiklPolikov @ Dec 26 2008, 10:23) *
Как записать во FLASH ?

Для начала прочитать в DS раздел Embedded Flash Controller (EFC).

Затем можно воспользоваться таким кодом:
Код
//******************************************************************************
//*    Flash service subroutines

#define    FMCN1        (0x30 << 0x10)
#define    FMCN1_5        (0x48 << 0x10)

int flash_write_page(u_int addr, u_char *data)
{
    u_int a, page;


    page = addr >> 8;

    AT91C_BASE_MC->MC_FMR = (AT91C_BASE_MC->MC_FMR & ~(AT91C_MC_FMCN | AT91C_MC_NEBP)) | FMCN1_5;

    a = 0;
    do
    {
        ((reg_32 *)AT91C_IFLASH)[a >> 2] =
            data[a] | (data[a + 1] << 8) | (data[a + 2] << 16) | (data[a + 3] << 24);
        a += 4;
    } while(a < AT91C_IFLASH_PAGE_SIZE);

    AT91C_BASE_MC->MC_FCR = (0x5a << 24) | ((page << 8) & AT91C_MC_PAGEN) | AT91C_MC_FCMD_START_PROG;

    while(!((a = AT91C_BASE_MC->MC_FSR) & AT91C_MC_FRDY));

    if((a & AT91C_MC_LOCKE) || (a & AT91C_MC_PROGE))
    {
        dprintf("Flash: Write Error (FSR = 0x%08x, Page = %03x).\r\n", a, page);
        return -1;
    }
    return 0;
}


Только нужно помнить, что читать flash во время записи нельзя, т.е. код должен быть расположен в RAM, любые обращения к flash во время записи (в прерываниях, например) должны быть исключены.
MiklPolikov
Цитата(aaarrr @ Dec 26 2008, 12:34) *
Только нужно помнить, что читать flash во время записи нельзя, т.е. код должен быть расположен в RAM, любые обращения к flash во время записи (в прерываниях, например) должны быть исключены.


Поясните пожалуйста !

Код расположен во flash , и следовательно пока он там я писать flash не могу.
После REMAP COMMAND выборка команд начнёт происходить из SRAM . А откуда они там возьмутся, если весь код изначально во flash ? Да и как код поместится в SRAM , ведь SRAM меньше чем flash ?

Возможно я должен сам переписать часть кода из flash в SRAM потом сделать REMAP ? А как быть с переменными которые в SRAM ?

Спасибо !
aaarrr
Вам нужно при помощи линкера разместить в RAM процедуру записи флеш (а не весь код!), которая будет выполняться при запрещенных прерываниях. Remap тут к делу не относится никак.
Artem_Petrik
Цитата(MiklPolikov @ Dec 26 2008, 10:23) *
at89sam7s128

Нужно сохранять данные при отключении питания.

Все же рекмоендую обдумать использование внешней I2C EEPROM. Стоит она копейки, при этом снимает много головной боли.
Шурила
Цитата(MiklPolikov @ Dec 26 2008, 09:23) *
sam7s128...

Как записать во FLASH ?

под IAR в примерах возьмите файл flash.c (я брал в IAR 5.0).
после внесения своих "рацух" rolleyes.gif у меня вышло так:
Код
__ramfunc int AT91F_Flash_Write( unsigned int Flash_Address ,int size ,unsigned int * buff){
  
  AT91PS_MC ptMC = AT91C_BASE_MC;    //* set the Flash controller base address
  unsigned int i, page, status;
  unsigned int * Flash;
  
  Flash = (unsigned int *) Flash_Address;    //* init flash pointer
  AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(72 <<16)) | AT91C_MC_FWS_1FWS;//        AT91F_Flash_Init();
  page = ((Flash_Address - (unsigned int)AT91C_IFLASH ) / FLASH_PAGE_SIZE_BYTE);   //* Get the Flash page number
  for (i=0; (i < FLASH_PAGE_SIZE_BYTE) & (size > 0);i++, Flash++,buff++,size-=4 ){   //* copy the new value
    *Flash=*buff;    //* copy the flash to the write buffer ensuring code generation
  }
  ptMC->MC_FCR = AT91C_MC_CORRECT_KEY | AT91C_MC_FCMD_START_PROG | (AT91C_MC_PAGEN & (page <<8));    //* Write the write page command
  status = 0;
  while ((status & AT91C_MC_FRDY) != AT91C_MC_FRDY ) {    //* Wait the end of command
    status = AT91C_BASE_MC->MC_FSR;
  }
  return status;        
}
Harbour
неплохо бы еще запрещать прерывания на момент записи, так как если код прерывания должен выполняться из флеш ...
Сергей Борщ
Цитата(Шурила @ Mar 31 2009, 03:56) *
после внесения своих "рацух" rolleyes.gif у меня вышло так:
А я еще больше ОЗУ сэкономил:
Код
----- flash.h: ---------
#ifndef FLASH_H__
#define FLASH_H__
#include    <stdint.h>
#include    <string.h>
#include    <ioAT91SAM7Sxx.h>

class flash_t
{
public:
    INLINE static void clear_buffer();
    INLINE static void fill(uint32_t const *addr, uint32_t data) { *(uint32_t *)addr = data; }
    INLINE static void fill(uint32_t const *dst, uint32_t *src, uint32_t size);
    INLINE static uint32_t read(uint32_t const *addr) { return *addr; }
    INLINE static void read(uint32_t *dst, uint32_t const *src, uint32_t size);
    INLINE static void erase(uint32_t const *page_addr);
    INLINE static void program(uint32_t const *page_addr);

    static uint32_t const PAGE_SIZE = 128;
private:
    static void command(uint32_t command, uint32_t mode);
    NOINLINE static void command_RAM(uint32_t command) __attribute__((section(".ramfunc")));
    
    static uint32_t const MCK_CYCLES = ((15ULL * MCK + 5000000ULL) / 10000000ULL);
public:
    static uint32_t const FLASH_WAITSTATES = MCK < 30000000ULL ? AT91C_MC_FWS_0FWS : AT91C_MC_FWS_1FWS;
} static Flash __attribute__((__unused__));

void flash_t::clear_buffer()
{
    uint_fast8_t Size = PAGE_SIZE / sizeof(uint32_t);
    uint32_t const *r = (uint32_t *)0;
    do
    {
        fill(r++, ~(uint32_t)0);
    }
    while (--Size);
}

void flash_t::fill(uint32_t const *dst, uint32_t *src, uint32_t size)
{
    do
    {
        *(uint32_t *)dst++ = *src++;
    }
    while (--size);
}

void flash_t::read(uint32_t *dst, uint32_t const *src, uint32_t size)
{
    do
    {
        *dst++ = *src++;
    }
    while (--size);
}

void flash_t::erase(uint32_t const *page_addr)
{
    command( ((AT91C_MC_KEY / 0xFFU) * 0x5A) | (((uint32_t)page_addr >> 7) << 8) | AT91C_MC_FCMD_START_PROG,
                (0 * AT91C_MC_FRDY) | (0 * AT91C_MC_LOCKE) | ( 0 * AT91C_MC_PROGE) |
                (0 * AT91C_MC_NEBP) | (FLASH_WAITSTATES) | (AT91C_MC_FMCN / 0xFFU * MCK_CYCLES)
           );
}

void flash_t::program(uint32_t const *page_addr)
{
    command( ((AT91C_MC_KEY / 0xFFU) * 0x5A) | (((uint32_t)page_addr >> 7) << 8) | AT91C_MC_FCMD_START_PROG,
                (0 * AT91C_MC_FRDY) | (0 * AT91C_MC_LOCKE) | ( 0 * AT91C_MC_PROGE) |
                (1 * AT91C_MC_NEBP) | (FLASH_WAITSTATES) | (AT91C_MC_FMCN / 0xFFU * MCK_CYCLES)
           );
}
#endif  // FLASH_H__

----- flash.cpp: ---------
#include    "Flash.h"
#include    "Interrupts.h"

void flash_t::command_RAM(uint32_t command) 
{
    AT91C_BASE_MC->MC_FCR = command;
    while(!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY))
      ;
}

void flash_t::command(uint32_t command, uint32_t mode) 
{
    disable_interrupts();
    AT91C_BASE_MC->MC_FMR = mode;
    command_RAM(command);
    enable_interrupts();
}
MiklPolikov
Цитата(aaarrr @ Mar 30 2009, 19:18) *
Вам нужно при помощи линкера разместить в RAM процедуру записи флеш (а не весь код!), которая будет выполняться при запрещенных прерываниях. Remap тут к делу не относится никак.


А где прочитать как это делается в KEIL ?
Подозреваю что Projekt > options for target > linker и там какой-то scatter file
aaarrr
В Keil'е оформляете процедуру примерно так:
Код
#pragma push
#pragma arm section code = "ramcode"
#pragma O1

void flash_subroutine(...)
{
    ...
}

#pragma pop


В scatter'е находите регион RAM и добавляете в него строку
Код
* (ramcode)


#pragma O1 нужна для обхода некого глюка RVDS (в Keil'е может его и нет), благодаря которому компилятор может инлайнить функции с явно определенной секцией в другие.
defunct
Не надо функции хранить в RAM. Функцию можно скопировать и выполнить из RAM самостоятельно в Run-time, чтобы RAM не занимать под мертвый код:

Код
// In-application flash programming for SAM7
#include "hal.h"
#include "syslib.h"
#include "iap.h"

#define FLASH_PAGE_SIZE_BYTES  256  // for SAM7S256/SAM7X256

#define FLASH_PROTECTION_KEY_FCR  (0x5A << 24)

#define CYCLES_PER_MICROSECOND ((CCLK / M))
#define CYCLES_FMCN  ((CYCLES_PER_MICROSECOND << 1)) // round up to 2 mks

typedef void __iap_exec_function( AT91PS_MC pMC, U32 FCR_val);


/***********************************************
* iap_FlashCmdFunc()                           *
*    This routine executes Flash command       *
* NOTE! THIS FUNCTION SHOULD BE COPIED INTO    *
* SRAM BEFORE EXECUTION                        *
* ---> pMC - pointer to memory controller      *
* ---> FCR_val - prepared FCR value            *
* <--- returns: nothing                        *
***********************************************/
void iap_FlashCmdFunc( AT91PS_MC pMC, U32 FCR_val)
{
    pMC->MC_FCR = FCR_val;
    // the EFC is locked... no reading from flash while writing..
    // the routine supposed to be called from RAM, lets wait until operation completes
    while (!(pMC->MC_FSR & AT91C_MC_FRDY));
}




/***********************************************
* iap_ExecCmd()                                *
*    This routine executes Flash command       *
* It places iap_FlashCmdFunc into SRAM, and    *
* does necessary stuff to call it              *
* Considering ARM and Thumb modes              *
* ---> FCR_val - prepared FCR value            *
* <--- returns: nothing                        *
***********************************************/
void iap_ExecCmd( U32 FCR_val)
{
    U8  buf[128]; // 128 bytes buffer
    U32 ThumbMode = (U32)iap_FlashCmdFunc & 0x01;

    {
        U32 iap_FuncAddr = (U32)iap_FlashCmdFunc & (~ThumbMode); // not even addr in thumb mode (have to & with ~0x01)
        AT91PS_AIC    pAIC = AT91C_BASE_AIC;
        AT91PS_MC    pMC = AT91C_BASE_MC;
        U32 iMask = pAIC->AIC_IMR;

        // copy function, that performs EFC command, into SRAM.
        memcpy_burst( (U32 *)buf, (U32 *)iap_FuncAddr, sizeof(buf));
        // disable all interrupt sources
        pAIC->AIC_IDCR = 0xFFFFFFFF;
        // execute function from SRAM (+1 to func addr in thumb mode)
        ((__iap_exec_function *)(buf + ThumbMode))( pMC, FCR_val);
        // restore interrupt sources
        pAIC->AIC_IECR = iMask;
    }
}



/***********************************************
* iap_PageWrite()                              *
*    The routine performs flash page write     *
* that uses abstract iap_ExecCmd() method      *  
*             WORKING VERSION                  *
* ---> FlashAddress - address of the flash     *
*      desired to be re-written                *
* ---> pPageData - pointer to the data array   *
* <--- returns: TRUE if flash-write performed  *
***********************************************/
int iap_PageWrite( U32 FlashAddress, U32 *pPageData, U32 size_bytes )
{
    AT91PS_MC    pMC = AT91C_BASE_MC;
    U32 FMRval = pMC->MC_FMR;
    U32 FCRval = FLASH_PROTECTION_KEY_FCR | (FlashAddress & 0x00FFF00) | AT91C_MC_FCMD_START_PROG;
    U32 *p = (U32 *)FlashAddress;
    if (size_bytes <= FLASH_PAGE_SIZE_BYTES)
    {
        U32 TotalCnt = FLASH_PAGE_SIZE_BYTES / sizeof( U32 );
        U32 Cnt = (size_bytes + 3) / sizeof( U32 );
        U32 tmp;

        // prepare Flash mode register
        // clear the NO-Erase before programming bit, and interrupt request flags
        FMRval &= ~(AT91C_MC_NEBP | AT91C_MC_FMCN | AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE);
        FMRval |=  (CYCLES_FMCN << 16);

        while (!(pMC->MC_FSR & AT91C_MC_FRDY));
        pMC->MC_FMR = FMRval;

        // write page data to the write buffer
        while(TotalCnt--)
        {
            if (Cnt)
            {
                *p++ = *pPageData++;
                Cnt -= 1;
            }
            else // read page data and write it back
            {
                tmp = *(V32 *)(p);
                *(V32 *)(p++) = tmp;
            }
        }

        // enter flash number and perform flash write operation
        iap_ExecCmd( FCRval );
        return TRUE;
    }
    return FALSE;
}


Учтены оба режима ARM/Thumb.
aaarrr
Способ потенциально небезопасный (iap_PageWrite не ROPI, размер его может и превысить 128 байт, стека может и не хватить и т.п.).
Стоит ли ради экономии полутора сотен байт RAM так напрягаться?
defunct
Цитата(aaarrr @ Apr 1 2009, 14:26) *
Способ потенциально небезопасный (iap_PageWrite не ROPI, размер его может и превысить 128 байт, стека может и не хватить и т.п.).
Стоит ли ради экономии полутора сотен байт RAM так напрягаться?

Стоит, т.к. лучше эту полусотню байт к стеку добавить.
Напряжений особых я тоже не вижу, нехватит 128 байт - дайте больше, можно не в стеке выделять а из heap или из пакетного пула (который всегда толстый при использовании EMAC) т.д..

PS: iap_PageWrite в RAM не копируется, ибо незачем, копируется только iap_FlashCmdFunc.
Пользователю предоставляется только iap_PageWrite(..) выполняемая из FLASH.
aaarrr
Цитата(defunct @ Apr 1 2009, 15:35) *
Стоит, т.к. лучше эту полусотню байт к стеку добавить.

На стеке это все же просто мертвый груз.

Цитата(defunct @ Apr 1 2009, 15:35) *
PS: iap_PageWrite в RAM не копируется, ибо незачем, копируется только iap_FlashCmdFunc.
Пользователю предоставляется только iap_PageWrite(..) выполняемая из FLASH.

Да, не заметил как-то, пардон. Тогда тем более лучше воткнуть эту процедуру средствами линкера, т.к. это даже меньше полусотни байт.
defunct
Цитата(aaarrr @ Apr 1 2009, 15:40) *
На стеке это все же просто мертвый груз.

Кто мертвый груз?
Освободившуюся память можете отдать под что угодно, как вариант - увеличить объем стека.
А Вы о чем?

Цитата
Тогда тем более лучше воткнуть эту процедуру средствами линкера, т.к. это даже меньше полусотни байт.

Не понимаю чем может быть статическое резервирование RAM, лучше динамического распределения.
Не стоит хранить в RAM код, который применяется раз в пятилетку.
aaarrr
Цитата(defunct @ Apr 1 2009, 16:55) *
Кто мертвый груз, вы о чем?

О том, что эти несчастные 128 байт надо добавить к стеку заранее, хотя задействованы они будут "раз в пятилетку".

Цитата(defunct @ Apr 1 2009, 16:55) *
Не понимаю чем может быть статическое резервирование RAM, лучше динамического распределения.
Не стоит хранить в RAM код, который применяется раз в пятилетку.

Хотя бы тем, что не будет такого маразма при каждом вызове iap_ExecCmd:
- выделили 128 байт на стеке
- скопировали туда 128 байт с начала iap_FlashCmdFunc, не разбираясь, надо ли так много
defunct
Цитата(aaarrr @ Apr 1 2009, 16:10) *
О том, что эти несчастные 128 байт надо добавить к стеку заранее, хотя задействованы они будут "раз в пятилетку".

Я так понимаю вы сейчас пишите в контексте, как бы это сказать, некоего ОСа, в котором используются отдельные маленькие стеки для каждой задачи. Верно? Если я прав, то конечно вам нельзя себе позволить разместить автоматическую 128-ми байтовую переменную в стеке. Но это сугубо ваша проблема, а не проблема предложенного подхода.

Я же пользую общий стек для всех задач, поэтому никогда не испытываю проблем с его объемом. Я могу себе позволить выделить в стеке буфер под например 1.5KB Ethernet пакет, без задней мысли. Поэтому выделить 128 байт в стеке это для меня не проблема, настолько же насколько объявиление переменной типа int.

к слову в оригинальном коде, память я выделяю из пакетного пула:
Код
void iap_ExecCmd( U32 FCR_val)
{
    PPACKET_BUF pPacketDesc = pool_AllocPart();
    U32 ThumbMode = (U32)iap_FlashCmdFunc & 0x01;

    while (!pPacketDesc)
    {
        Kernel_Dispatch();
        pPacketDesc = pool_AllocPart();
    }
    ...


А специально для форума подготовил код использующий стек-фрейм, т.к. он получается отвязанным от конкретной реализации.

Большой стек у меня получается вчастности за счет того, что в программе практически нет лишнего статически распределенного мусора. Как например функций записи страницы флеш.

Цитата
Хотя бы тем, что не будет такого маразма при каждом вызове iap_ExecCmd:
- выделили 128 байт на стеке
- скопировали туда 128 байт с начала iap_FlashCmdFunc, не разбираясь, надо ли так много

С другой стороны не будет и такого маразма как в вашей реализации:
- Откусили ~n-байт от RAM (которого и так не много) навсегда;
- мало того еще надо лезть и править скрипт линкера;
- при переносе программы между компиляторами код работать не будет, т.к. надо еще и учитывать особенности компилятора.

Насчет скопировали неразбираясь надо ли так много, а стоит ли оно того это разбирательство? По скорости никто не жмет, т.к. непосредственно запись страницы флеш длится на порядки дольше чем это избыточное копирование.
aaarrr
Цитата(defunct @ Apr 1 2009, 18:30) *
Но это сугубо ваша проблема, а не проблема предложенного подхода.

Нет, не моя. Выделять на стеке огромные объекты - это не лучший подход в любом случае.

Цитата(defunct @ Apr 1 2009, 18:30) *
С другой стороны не будет и такого маразма как в вашей реализации:
- Откусили ~n-байт от RAM (которого и так не много) навсегда;
- мало того еще надо лезть и править скрипт линкера;
- при переносе программы между компиляторами код работать не будет, т.к. надо еще и учитывать особенности компилятора.

n в районе <50, неужели в ваших проектах настолько плохо с RAM?
Владение инструментарием - это норма, а не маразм.
defunct
Цитата(aaarrr @ Apr 1 2009, 18:11) *
Нет, не моя. Выделять на стеке огромные объекты - это не лучший подход в любом случае.

128 байт это не огромный объем, это сравнимо с контекстом регистров процессора (16x4), поэтому не делайте из мухи слона на ровном месте.

Цитата
n в районе <50, неужели в ваших проектах настолько плохо с RAM?

Как говорится, с мира по нитке, глядиш и набежит KB, а это уже существенно.

Цитата
Владение инструментарием - это норма, а не маразм.

Выделили и скопировали - это тоже норма, а не маразм, при динамическом распределении памяти.
aaarrr
Цитата(defunct @ Apr 1 2009, 19:34) *
Как говорится, с мира по нитке, глядиш и набежит KB, а это уже существенно.

И кто теперь делает из мухи слона?

Цитата(defunct @ Apr 1 2009, 19:34) *
Выделили и скопировали - это тоже норма, а не маразм, при динамическом распределении памяти.

Только скопировали то, что:
1. Сгенерировано компилятором
2. Для вырезания и копирования не предназначено

Т.е. теоретически имеет право не работать.
defunct
Цитата
Только скопировали то, что:
1. Сгенерировано компилятором
2. Для вырезания и копирования не предназначено

Т.е. теоретически имеет право не работать.

Если бы мы обсуждали некий гипотетический способ достижения цели, можно было бы порассуждать теоретически.
А так имеется конкретный __рабочий__ код, стоит ли вспоминать о его теоретическом праве? ;>
aaarrr
Цитата(defunct @ Apr 1 2009, 19:51) *
Если бы мы обсуждали некий гипотетический способ достижения цели, можно было бы порассуждать теоретически.
А так имеется конкретный __рабочий__ код, стоит ли вспоминать о его теоретическом праве? ;>

Этот "рабочий" код с легкостью может реализовать свое право и стать __нерабочим__ при смене компилятора или опций оптимизации.
defunct
Цитата(aaarrr @ Apr 1 2009, 18:55) *
Этот "рабочий" код с легкостью может реализовать свое право и стать __нерабочим__ при смене компилятора или опций оптимизации.

Ключевое слово "может" реализовать, и также слегкостью может и не реализовать.
Для успокоения, можно отключить оптимизацию одной функции (той что копируется), но думаю и этого делать не потребуется.

В отличие от вашего подхода, когда код жестко привязывается к конкретному компилятору, и при переносе однозначно становится нерабочим.
aaarrr
Цитата(defunct @ Apr 1 2009, 21:00) *
В отличие от вашего подхода, когда код жестко привязывается к конкретному компилятору, и при переносе однозначно становится нерабочим.

Код у меня ни к чему не привязывается, а уж скрипт линкера в любом случае менять придется. И нерабочим такой код назвать нельзя, тут вы теплое с мягким путаете.

Цитата(defunct @ Apr 1 2009, 21:00) *
Ключевое слово "может" реализовать, и также слегкостью может и не реализовать.

При переходе дороги на красный свет вас может сбить машина. Так что, будем ломиться на красный?
defunct
Цитата(aaarrr @ Apr 1 2009, 20:17) *
а уж скрипт линкера в любом случае менять придется.

Зачем его менять в любом случае?
Кто мешает писать так, чтобы не надо было менять.

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

некоторые компиляторы требуют атрибут __ram, и т.п. так, что ничего я не путаю.

Цитата(aaarrr @ Apr 1 2009, 20:17) *
При переходе дороги на красный свет вас может сбить машина. Так что, будем ломиться на красный?

А почему бы и нет, если есть подземный переход.
Конечно, для тех кто привык всегда по поверхности - подземка не подойдет.
aaarrr
Цитата(defunct @ Apr 1 2009, 21:34) *
Зачем его менять в любом случае?
Кто мешает писать так, чтобы не надо было менять.

Никто не мешает, если это не противоречит правилам. Ваш пример противоречит.
Хотите использовать какой-нибудь simple memory map и визарды - да флаг в руки, только далеко не всегда это возможно.

Цитата(defunct @ Apr 1 2009, 21:34) *
...ничего я не путаю.

Работоспособность кода и возможность собрать его компиляторами X и Y - абсолютно разные вещи.

Цитата(defunct @ Apr 1 2009, 21:34) *
А почему бы и нет, если есть подземный переход.
Конечно, для тех кто привык всегда по поверхности - подземка не подойдет.

Это не подземный переход, а канализационный коллектор.
defunct
Цитата(aaarrr @ Apr 1 2009, 20:44) *
Ваш пример противоречит.

Вашим правилам он противоречит что ли? Ну так не делайте так, если он противоречит вашим правилам.

Цитата
Работоспособность кода и возможность собрать его компиляторами X и Y - абсолютно разные вещи.

Невозможность собрать приводит к неработоспособности кода. очевидно.
aaarrr
Цитата(defunct @ Apr 1 2009, 22:34) *
Вашим правилам он противоречит что ли? Ну так не делайте так, если он противоречит вашим правилам.

И моим в том числе. Делать не буду, и другим не советую.

Цитата(defunct @ Apr 1 2009, 22:34) *
Невозможность собрать приводит к неработоспособности кода. очевидно.

Невозможность собрать приводит к отсутствию предмета как такового, ничуть не влияя на его потенциальную работоспособность.
defunct
Цитата(aaarrr @ Apr 1 2009, 21:58) *
Делать не буду, и другим не советую.

А я советую делать так. По крайней мере для сохранения конфигурации способ идеален по следующим причинам:

1. Накладные постоянные расходы RAM - 0.
2. Код всегда лежит во флеш, т.о. он не может быть случайно перетерт.
3. Можно забыть, что такое скрипты линкера.
4. Вопреки опасениям уважаемого aaarrr, никаких проблем с переносом между компиляторами и установленным уровнем оптимизации нет. Специально попробовал в трех компиляторах IAR 4.40, RVDS 3.1 и Keil CA последний, все с максимальным уровнем оптимизации (т.е. один раз написав код, перенос между компиляторами не требует никаких правок, ни сам код ни скрипты ничего менять не надо). Ну а если вдруг при использовании какого-то компилятора (допускаю) случится худшее и код откажется работать, нужно будет отключить оптимизацию одной функции (iap_FlashCmdFunc() в примере) и все.
aaarrr
Цитата(defunct @ Apr 2 2009, 00:26) *
1. Накладные постоянные расходы RAM - 0.

Даже с этим можно поспорить, если нет кучи или другого подобного источника памяти.

Цитата(defunct @ Apr 2 2009, 00:26) *
2. Код всегда лежит во флеш, т.о. он не может быть сучайно перетерт.

В нормальной программе ничего не может быть случайно перетерто.

Цитата(defunct @ Apr 2 2009, 00:26) *
3. Можно забыть, что такое скрипты линкера.

Но лучше все же помнить.

Цитата(defunct @ Apr 2 2009, 00:26) *
4. Вопреки предположениям уважаемого aaarrr, никаких проблем с переносом между компиляторами и установленным уровнем оптимизации, специально попробовал в трех компиляторах IAR 4.40, RVDS 3.1 и Keil CA последний, все с максимальным уровнем оптимизации (т.е. один раз написав код, перенос между компиляторами не требует никаких правок).

Для данного конкретного случая вполне очевидный результат. Но сам принцип глубоко порочен - нельзя в общем случае копировать кота в мешке.

Можно написать эту процедуру на асме, тем самым гарантировав ее переносимость, и спокойно копировать в ОЗУ. Но нельзя переносить результат работы компилятора. Даже когда все кажется очевидным и безопасным.
defunct
Цитата(aaarrr @ Apr 1 2009, 23:51) *
Можно написать эту процедуру на асме, тем самым гарантировав ее переносимость, и спокойно копировать в ОЗУ.

Или наоборот непереносимость, т.к. ситаксис ассемблера может отличаться.

Да и вы начинаете сами себе противоречить.
то
Цитата
Для данного конкретного случая вполне очевидный результат.

то
Цитата
Но нельзя переносить результат работы компилятора. Даже когда все кажется очевидным и безопасным.

Проще надо быть. Когда пишешь безопасный код, то и компилятор сделает все безопасно на выходе.
Поэтому нет нужды тратить свое время на рожание асм кода, компилятор - сгенерирует тоже самое быстрее и дешевле.
Есть сомнения, загляните в листинг. Не работает - исправьте.
aaarrr
Цитата(defunct @ Apr 2 2009, 01:29) *
Или наоборот непереносимость, т.к. ситаксис ассемблера может отличаться.

Переносимость не в смысле "возможность компиляции тулзом X" (что я вообще не считаю проблемой), а в смысле "возможность работы из любого адреса".

Цитата(defunct @ Apr 2 2009, 01:29) *
Проще надо быть. Когда пишешь безопасный код, то и компилятор сделает все безопасно на выходе.

Вы не можете заранее знать, безопасно ли менять рабочий адрес процедуры. Если она, конечно, не состоит из шести команд (целых 24 байта ОЗУ сэкономили!) как в данном случае.
defunct
Цитата(aaarrr @ Apr 2 2009, 00:44) *
Переносимость не в смысле "возможность компиляции тулзом X" (что я вообще не считаю проблемой), а в смысле "возможность работы из любого адреса".

Ок, хорошо, с такой точки зрения согласен.
Но переносимость всмысле "возможность компиляции тулзом X" теряется. Хоть это и не проблема - но это время, наше время!
Зачем самое дорогое что есть, тратить на адаптацию кода к тулзу X?

Цитата
Вы не можете заранее знать, безопасно ли менять рабочий адрес процедуры.

Если она не содержит вызовов других функций, и не использует глобальных переменных, можно спокойно прогнозировать ее поведение при выполнении с любого адреса.
(т.е. важно чтобы функция всего навсего не содержала в себе адресацию через PC).
Как достичь - передать ей все требуемые данные в качестве параметров.

Цитата
Если она, конечно, не состоит из шести команд (целых 24 байта ОЗУ сэкономили!) как в данном случае.

smile.gif тем не менее 24 байта сэкономлено.
aaarrr
Цитата(defunct @ Apr 2 2009, 02:08) *
Зачем самое дорогое что есть, тратить на адаптацию кода к тулзу X?

Можно вместо асма машинным кодом забить - будет на 100% переносимо. Отличный вариант, кстати.

Цитата(defunct @ Apr 2 2009, 02:08) *
Если она не содержит вызовов других функций, и не использует глобальных переменных, ...

...и не использует "сложных" констант.
defunct
Цитата(aaarrr @ Apr 2 2009, 01:39) *
Можно вместо асма машинным кодом забить - будет на 100% переносимо. Отличный вариант, кстати.

Бесспорно отличный вариант как для себя, но плохо читаемо если выкладывать...

Цитата
...и не использует "сложных" констант.

Да, и их тоже, разумеется.

Надеюсь вы согласитесь, что непосредственно код примера - безопасен.
aaarrr
Получается нечто вроде:
Код
void fcmd(U32 fcr)
{
    U32 ramcmd[6] =
    {
        0xe3a01000, // MOV      r1,#0
        0xe501009c, // STR      r0,[r1,#-0x9c]; MC_FCR
        0xe5110098, // LDR      r0,[r1,#-0x98]; MC_FSR
        0xe3100001, // TST      r0,#1
        0x0afffffc, // BEQ      {pc} - 0x8
        0xe12fff1e  // BX       r14
    };
    void (*pcmd)(U32) = *(void (*)(U32))&ramcmd;

    pcmd(fcr);
}


Вполне работоспособно и переносимо. Но я бы все же предпочел вариант с линкером.

Цитата(defunct @ Apr 2 2009, 02:55) *
Надеюсь вы согласитесь, что непосредственно код примера - безопасен.

О да, вполне. Просто кто-нибудь мог экстраполировать результат на другой код и поиметь проблем.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.