Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Внутренний flash для хранения пользовательских данных
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
athlon64
В процессоре at91sam7x512 нужно отдать последние 128Кб для хранения настроек устройства (конфигурационного файла).
Запись и чтение у меня сделано и работает, но начиная с определённого размера конфигурации, запись повреждает основную программу.
В icf-файле уменьшил адрес конца ROM __ICFEDIT_region_ROM_end__ со стандартных 0x17FFFF до 0x15FFFF, чтобы линкер не помещал программу выше 384Кб флеша. Но, видимо, этого недостаточно.
Как правильно настроить линкер?
athlon64
Посмотрел map-файл, линкер действительно не помещает ничего выше адреса 0x0015FFFF, так что видимо дело не в том что область основной программы пересекается с областью конфигурации, а в том что во время записи конфигурации возникает прерывание от TWI и при этом каким то образом повреждается основная программа.
В связи с этим вопрос: как лучше всего корректно отключить прерывания от TWI на время записи во flash?
cornflyer
проверь содержимое Flash Mode Register: AT91C_BASE_MC->MC_FMR
Warning: In order to guarantee valid operations on the flash memory, the field Flash Microsecond Cycle Number (FMCN)
must be correctly programmed.

у меня например MCK = 10MHz
соответственно в LowLevelInit() у меня есть такая строчка:
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(10<<16)) | AT91C_MC_FWS_0FWS; // 1us =< 10 MCK ticks

если у тебя MCK = 48 MHz тогда должно быть так:
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(50<<16)) | AT91C_MC_FWS_0FWS; // 1us =< 50 MCK tick

athlon64
Цитата(cornflyer @ Jul 6 2010, 11:42) *
проверь содержимое Flash Mode Register: AT91C_BASE_MC->MC_FMR
Warning: In order to guarantee valid operations on the flash memory, the field Flash Microsecond Cycle Number (FMCN)
must be correctly programmed.

у меня например MCK = 10MHz
соответственно в LowLevelInit() у меня есть такая строчка:
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(10<<16)) | AT91C_MC_FWS_0FWS; // 1us =< 10 MCK ticks

если у тебя MCK = 48 MHz тогда должно быть так:
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(50<<16)) | AT91C_MC_FWS_0FWS; // 1us =< 50 MCK tick

У меня в LowLevelInit():
Код
AT91C_BASE_EFC0->EFC_FMR = AT91C_MC_FWS_1FWS;
AT91C_BASE_EFC1->EFC_FMR = AT91C_MC_FWS_1FWS;

А AT91C_MC_FWS равно:
Код
#define     AT91C_MC_FWS_0FWS                 (0x0 <<  8) // (EFC) 1 cycle for Read, 2 for Write operations
#define     AT91C_MC_FWS_1FWS                 (0x1 <<  8) // (EFC) 2 cycles for Read, 3 for Write operations
#define     AT91C_MC_FWS_2FWS                 (0x2 <<  8) // (EFC) 3 cycles for Read, 4 for Write operations
#define     AT91C_MC_FWS_3FWS                 (0x3 <<  8) // (EFC) 4 cycles for Read, 4 for Write operations

Пробовал AT91C_MC_FWS_2FWS, AT91C_MC_FWS_3FWS - ничего не меняет.
При AT91C_MC_FWS_0FWS проц вообще не стартует
cornflyer
пропиши строчку:
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(50<<16)) | AT91C_MC_FWS_1FWS; // 1us =< 50 MCK tick

где вместо 50 укажи свое значение, т.е. >=MCK[MHz]
например если MCK = 48MHz, тогда округляешь до большего числа, т.е. до 50

в мануале на AT91SAM7 так написано, иначе флэш будет работать с глюками
athlon64
Цитата(cornflyer @ Jul 6 2010, 12:14) *
пропиши строчку:
AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(50<<16)) | AT91C_MC_FWS_1FWS; // 1us =< 50 MCK tick

где вместо 50 укажи свое значение, т.е. >=MCK[MHz]
например если MCK = 48MHz, тогда округляешь до большего числа, т.е. до 50

в мануале на AT91SAM7 так написано, иначе флэш будет работать с глюками

У sam7x512 два EFC, поэтому вписал:
Код
AT91C_BASE_EFC0->EFC_FMR = ((AT91C_MC_FMCN)&(50<<16)) | AT91C_MC_FWS_1FWS; // 1us =< 50 MCK tick
AT91C_BASE_EFC1->EFC_FMR = ((AT91C_MC_FMCN)&(50<<16)) | AT91C_MC_FWS_1FWS; // 1us =< 50 MCK tick

К сожалению, не помогло
cornflyer
выкладывай код функций чтения/записи....
во время работы с флешью надо запрещать все прерывания:

__disable_interrupt();

// flash read/write

__enable_interrupt();

причем надо еще добавить в startup.s:


irqHandler:
// spurious interrupts elimination
MRS r14, SPSR ; Abort if IRQ disabled
ANDS r14, r14, #I_BIT ; (IRQ_BIT = 1)
LDMNEFD sp!, {pc}^
athlon64
Цитата(cornflyer @ Jul 6 2010, 13:37) *
во время работы с флешью надо запрещать все прерывания:
__disable_interrupt();
// flash read/write
__enable_interrupt();
причем надо еще добавить в startup.s:

irqHandler:
// spurious interrupts elimination
MRS r14, SPSR ; Abort if IRQ disabled
ANDS r14, r14, #I_BIT ; (IRQ_BIT = 1)
LDMNEFD sp!, {pc}^

на __disable_interrupt(); и __enable_interrupt(); IAR ругается
Я пробовал запрещать прерывания от TWI с помощью:
AT91C_BASE_TWI->TWI_IDR = 0xFFFFFFFF; и IRQ_DisbleIT(AT91C_ID_TWI);
не помогло.
Если не инициализировать TWI - запись и чтение происходят без ошибок. Причём с включенным TWI запись конфигурационного файла до 256 байт тоже проходит без ошибок, больше 256 - виснет и после резета виснет снова, т.е. как будто повреждена основная программа.

Вот код чтения:
Код
char EPR_Rd(unsigned int adr)
{
  return((char) *(pfirstPageData+adr));
}


Запись - функция реализующая запись в произвольное место произвольное кол-во байт:
Код
volatile unsigned int firstPageAddress;
volatile unsigned int *pfirstPageData;                 // Указатель на начало пользовательского блока во FLASH
unsigned int pFlashBuffer[AT91C_IFLASH_PAGE_SIZE / 4]; // Буфер записи страницы flash

void WriteBlokToFlash(unsigned int address_wr, char *data_array_p, unsigned char IndexStartWr, unsigned int CntByte_wr)
{
  unsigned int BytesSaved, i;
  unsigned char PageNoStart, AddrInPage, i_end;
  unsigned char array_idx=0;

  BytesSaved=0;                                             // Пока не записали ни одного байта конфигурации      
  
  while (BytesSaved!=CntByte_wr)                            // Сидим в цикле до тех пор пока всё запланированное не будет записано
  {
    PageNoStart = address_wr/64;                              // Номер страницы для записи
    AddrInPage  = address_wr%64;                              // Адрес внутри страницы  
    
    for (i=0;i<64;i++)
      pFlashBuffer[i] = *(pfirstPageData+(PageNoStart*64)+i); // Загоняем в буфер текущую страницу флеша
    
    if ((AddrInPage+CntByte_wr)>64)                         // Если блок не умещается в текущую страницу пишем до конца страницы (64*4байт)
      i_end=64;
    else                                                    // Если умещается - пишем до конца блока
      i_end = AddrInPage + CntByte_wr - BytesSaved;
    
    array_idx = IndexStartWr + BytesSaved;                  // Ставим указатель в массиве данных
    for (i=AddrInPage; i<i_end; i++)
    {
      pFlashBuffer[i]=*(data_array_p+(array_idx++));        // Вносим изменения в буфер записи
      BytesSaved++;
    }
    FLASHD_Write(firstPageAddress+(PageNoStart*AT91C_IFLASH_PAGE_SIZE), pFlashBuffer, AT91C_IFLASH_PAGE_SIZE);
    address_wr = address_wr + BytesSaved;                   // Увеличиваем адрес на кол-во записанных байт
  }      
}

Щас появилась мысль:
Конфигурация пишется пачками по 62 байта, обычно затык на 5 пакете, т.е. который попадает между 2х страниц, соответственно эта функция произведёт запись 2х страниц почти подряд. Возможно не хватает времени на запись первой страницы, как нужно писать уже вторую? Попробую сделать задержку. Но тогда не понятно почему с отключенным TWI запись и такой конфигурации проходит нормально
cornflyer
добавь в main.c
#include <intrinsics.h>

тогда иар ругатся не будет
__enable_interrupt(); // это глобальное прерывание
athlon64
Цитата(cornflyer @ Jul 6 2010, 14:14) *
добавь в main.c
#include <intrinsics.h>

тогда иар ругатся не будет
__enable_interrupt(); // это глобальное прерывание

Конфигурация 272 байта:
Теперь из 5 пачек по 62 байта пишет все
Тут же при контрольном чтении читает 4 и виснет

Конфигурация 968 байт:
Пишет успешно 3 пачки по 62 байта и виснет

Конфигурация 348 байт:
Пишется 5 пачек по 62 байт и виснет
При повторной записи виснет после 2 пачек

Во всех случаях после резета начинает выполнять программу и зависает

Вот такие вот дела sad.gif
cornflyer
я к сожалению только сейчас получил возможность пощупать at91sam7
до этого момента работал c процами NXP
для хранения конфигов ставил внешнюю SPI EEPROM
как вариант AT24C1024BW-SH25-B - EEPROM SERIAL 2.7-5.5V
Memory Configuration:128K x 8bit
Interface:Serial, 2 Wire
Clock Frequency:1MHz
dimka76
Функция
Код
FLASHD_Write(firstPageAddress+(PageNoStart*AT91C_IFLASH_PAGE_SIZE), pFlashBuffer, AT91C_IFLASH_PAGE_SIZE);


у вас откуда исполняется? Из FLASH или из RAM ?
athlon64
Цитата(dimka76 @ Jul 7 2010, 13:05) *
Функция
Код
FLASHD_Write(firstPageAddress+(PageNoStart*AT91C_IFLASH_PAGE_SIZE), pFlashBuffer, AT91C_IFLASH_PAGE_SIZE);


у вас откуда исполняется? Из FLASH или из RAM ?

Из flash
defunct
Цитата(athlon64 @ Jul 6 2010, 17:11) *
Во всех случаях после резета начинает выполнять программу и зависает

Вот такие вот дела sad.gif

Для того чтобы функции __enabled_interrupt() и __disable_interrupts() работали, необходимо чтобы проц был в SYS или SVC режиме.
В USR mode эти фукнции работать не будут.

В USR mode запретить прерывания можно так:
Код
U32 iMask = pAIC->AIC_IMR;
pAIC->AIC_IDCR = 0xFFFFFFFF;

// execute function from SRAM
...

// restore interrupt sources
pAIC->AIC_IECR = iMask;


Цитата(athlon64 @ Jul 7 2010, 10:18) *
Из flash

А надо из RAM.
athlon64
В общем разобрался в ситуации, дело было не в бобине как грится smile.gif
Проблема была не с записью флеш. Процессор зависал при попытке выполнить конфигурационные команды в процессе записи конфигурации. Т.е. блокировки на время записи не было, точнее она была закомментирована и забыта.
Отключение инициализации TWI помогало потому что в том же цикле, где лежит исполнение конфигурации, инициировался обмен по TWI, который занимал его флагом и никогда не освобождал (т.к. прерывания были отключены) и выполнение конфигурации было запрещено, соответственно флеш записывался корректно.
Т.о. запись/чтение работали нормально smile.gif
Тем не менее, было принято решение не хранить конфигурацию во внутреннем флеше. Теперь для этого используется AT45DB321.
Всех благодарю за наводки и комментарии smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.