|
Программная запись FLASH AT91SAM7S128 |
|
|
|
Dec 26 2008, 08:34
|
Гуру
     
Группа: Свой
Сообщений: 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 во время записи (в прерываниях, например) должны быть исключены.
|
|
|
|
|
Mar 30 2009, 14:55
|

Гуру
     
Группа: Свой
Сообщений: 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
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Mar 30 2009, 15:32
|
Местный
  
Группа: Свой
Сообщений: 443
Регистрация: 22-07-06
Из: Украина, г. Харьков
Пользователь №: 19 006

|
Цитата(MiklPolikov @ Dec 26 2008, 10:23)  at89sam7s128
Нужно сохранять данные при отключении питания. Все же рекмоендую обдумать использование внешней I2C EEPROM. Стоит она копейки, при этом снимает много головной боли.
|
|
|
|
|
Mar 31 2009, 00:56
|

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

|
Цитата(MiklPolikov @ Dec 26 2008, 09:23)  sam7s128...
Как записать во FLASH ? под IAR в примерах возьмите файл flash.c (я брал в IAR 5.0). после внесения своих "рацух"  у меня вышло так: Код __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; }
|
|
|
|
|
Mar 31 2009, 07:16
|

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

|
Цитата(Шурила @ Mar 31 2009, 03:56)  после внесения своих "рацух"  у меня вышло так: А я еще больше ОЗУ сэкономил: Код ----- 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)
|
|
|
|
|
Mar 31 2009, 14:07
|
Гуру
     
Группа: Свой
Сообщений: 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'е может его и нет), благодаря которому компилятор может инлайнить функции с явно определенной секцией в другие.
|
|
|
|
|
Apr 1 2009, 11:01
|

кекс
     
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Apr 1 2009, 11:35
|

кекс
     
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Apr 1 2009, 12:40
|
Гуру
     
Группа: Свой
Сообщений: 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. Да, не заметил как-то, пардон. Тогда тем более лучше воткнуть эту процедуру средствами линкера, т.к. это даже меньше полусотни байт.
|
|
|
|
|
Apr 1 2009, 12:55
|

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

|
Цитата(aaarrr @ Apr 1 2009, 15:40)  На стеке это все же просто мертвый груз. Кто мертвый груз? Освободившуюся память можете отдать под что угодно, как вариант - увеличить объем стека. А Вы о чем? Цитата Тогда тем более лучше воткнуть эту процедуру средствами линкера, т.к. это даже меньше полусотни байт. Не понимаю чем может быть статическое резервирование RAM, лучше динамического распределения. Не стоит хранить в RAM код, который применяется раз в пятилетку.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|