реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Программная запись FLASH AT91SAM7S128
MiklPolikov
сообщение Dec 26 2008, 07:23
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702



at89sam7s128

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

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

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

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

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


Спасибо !

Сообщение отредактировал MiklPolikov - Dec 26 2008, 07:24


--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Dec 26 2008, 08:34
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(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 во время записи (в прерываниях, например) должны быть исключены.
Go to the top of the page
 
+Quote Post
MiklPolikov
сообщение Mar 30 2009, 14:55
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702



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


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

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

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

Спасибо !

Сообщение отредактировал MiklPolikov - Mar 30 2009, 14:56


--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 30 2009, 15:18
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Вам нужно при помощи линкера разместить в RAM процедуру записи флеш (а не весь код!), которая будет выполняться при запрещенных прерываниях. Remap тут к делу не относится никак.
Go to the top of the page
 
+Quote Post
Artem_Petrik
сообщение Mar 30 2009, 15:32
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 443
Регистрация: 22-07-06
Из: Украина, г. Харьков
Пользователь №: 19 006



Цитата(MiklPolikov @ Dec 26 2008, 10:23) *
at89sam7s128

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

Все же рекмоендую обдумать использование внешней I2C EEPROM. Стоит она копейки, при этом снимает много головной боли.
Go to the top of the page
 
+Quote Post
Шурила
сообщение Mar 31 2009, 00:56
Сообщение #6


Частый гость
**

Группа: Свой
Сообщений: 81
Регистрация: 28-07-07
Из: Кишинев
Пользователь №: 29 434



Цитата(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;        
}
Go to the top of the page
 
+Quote Post
Harbour
сообщение Mar 31 2009, 05:44
Сообщение #7


Местами Гуру
*****

Группа: Validating
Сообщений: 1 103
Регистрация: 5-12-04
Пользователь №: 1 323



неплохо бы еще запрещать прерывания на момент записи, так как если код прерывания должен выполняться из флеш ...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 31 2009, 07:16
Сообщение #8


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Шурила @ 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();
}


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MiklPolikov
сообщение Mar 31 2009, 14:00
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702



Цитата(aaarrr @ Mar 30 2009, 19:18) *
Вам нужно при помощи линкера разместить в RAM процедуру записи флеш (а не весь код!), которая будет выполняться при запрещенных прерываниях. Remap тут к делу не относится никак.


А где прочитать как это делается в KEIL ?
Подозреваю что Projekt > options for target > linker и там какой-то scatter file


--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 31 2009, 14:07
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



В Keil'е оформляете процедуру примерно так:
Код
#pragma push
#pragma arm section code = "ramcode"
#pragma O1

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

#pragma pop


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


#pragma O1 нужна для обхода некого глюка RVDS (в Keil'е может его и нет), благодаря которому компилятор может инлайнить функции с явно определенной секцией в другие.
Go to the top of the page
 
+Quote Post
defunct
сообщение Apr 1 2009, 11:01
Сообщение #11


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Не надо функции хранить в 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.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 1 2009, 11:26
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Способ потенциально небезопасный (iap_PageWrite не ROPI, размер его может и превысить 128 байт, стека может и не хватить и т.п.).
Стоит ли ради экономии полутора сотен байт RAM так напрягаться?
Go to the top of the page
 
+Quote Post
defunct
сообщение Apr 1 2009, 11:35
Сообщение #13


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



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

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

PS: iap_PageWrite в RAM не копируется, ибо незачем, копируется только iap_FlashCmdFunc.
Пользователю предоставляется только iap_PageWrite(..) выполняемая из FLASH.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Apr 1 2009, 12:40
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(defunct @ Apr 1 2009, 15:35) *
Стоит, т.к. лучше эту полусотню байт к стеку добавить.

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

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

Да, не заметил как-то, пардон. Тогда тем более лучше воткнуть эту процедуру средствами линкера, т.к. это даже меньше полусотни байт.
Go to the top of the page
 
+Quote Post
defunct
сообщение Apr 1 2009, 12:55
Сообщение #15


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(aaarrr @ Apr 1 2009, 15:40) *
На стеке это все же просто мертвый груз.

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

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

Не понимаю чем может быть статическое резервирование RAM, лучше динамического распределения.
Не стоит хранить в RAM код, который применяется раз в пятилетку.
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 23:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01509 секунд с 7
ELECTRONIX ©2004-2016