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

 
 
> Проблемы при работе со встроенной flash, AT91SAM7A3, bootloader
Costa
сообщение Feb 4 2009, 17:34
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 24-12-08
Пользователь №: 42 726



Здравствуйте!

Делаю загрузчик (bootloader) для AT91SAM7A3, одной из функций которого должно быть обновление (через USART, но это не суть) собственной прошивки. Все получается, из под JTAG, т.е. когда код загрузчика расположен и исполняется в RAM, все замечательно работает.
Проблема возникает, когда этот же код зашивается во flash. Когда дело доходит собственно до работы с flash (lock/unlock, write page), программа зависает, а поскольку в устройстве есть внешний watchdog, происходит reset.

Сделал маленькую функцию, которая блокирует (lock) регион 0 flash:
Код
__ramfunc void Lock(void)
{
    unsigned int interrupt_mask;
    unsigned int flash_status;
    unsigned short lock_status = *AT91C_MC_FSR >> 16;
    if (lock_status & 0x1)
        return;
  *AT91C_MC_FMR = FMCN_FOR_LOCK | AT91C_MC_FWS_1FWS;
    interrupt_mask = *AT91C_AIC_IMR;
  *AT91C_AIC_IDCR = AT91C_ALL_INT;
  *AT91C_MC_FCR = AT91C_MC_KEY | AT91C_MC_FCMD_LOCK;
  do
  {
    flash_status = *AT91C_MC_FSR & AT91C_MC_EOL;
  }
  while (!flash_status);
  *AT91C_AIC_IECR = interrupt_mask;
}

Штука в том, что собственно lock происходит, т.к. после reset функция выскакивает по первому return; - но вот если регион в состоянии unlock, то все стопорится в цикле do while. Причем пробовал тупо вставлять счетчик в тело цикла, чтобы по его окончании выходить из цикла - все равно виснет...
Уже весь мозг сломал и не знаю, в какую сторону рыть. То ли проблема в том, что как-то некорректно выключаются прерывания на время операций с flash, т.к. хотя сами обработчики прерываний и сделаны __ramfunc, но есть еще вектора прерываний, обертка... То ли вышеприведенный код не попадает на самом деле в RAM, хотя в стартапе __segment_init прописан, и соотв. библиотека к проекту подключена... Помогите разобраться, где накосячил.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 8)
aaarrr
сообщение Feb 4 2009, 18:12
Сообщение #2


Гуру
******

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



Для начала убедитесь, что код действительно в RAM - проверьте map-файл. Прерывания я бы запрещал на уровне ядра, а не AIC'а.
Go to the top of the page
 
+Quote Post
Costa
сообщение Feb 5 2009, 06:44
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 24-12-08
Пользователь №: 42 726



Цитата(aaarrr @ Feb 4 2009, 21:12) *
Для начала убедитесь, что код действительно в RAM - проверьте map-файл. Прерывания я бы запрещал на уровне ядра, а не AIC'а.

Вот вырезки из map-файла:

Код
#                            (-carm -Z(CONST)INTRAMSTART_REMAP=00200000        #
#                            -Z(CONST)INTRAMEND_REMAP=00207FFF                 #
#                            -DROMSTART=00000000 -DROMEND=00004000             #
#                            -DRAMSTART=00200000 -DRAMEND=00207FFF             #
#                            -Z(CODE)INTVEC=00-3F                              #
#                            -Z(CODE)ICODE,DIFUNCT=ROMSTART-ROMEND             #
#                            -Z(CODE)SWITAB=ROMSTART-ROMEND                    #
#                            -Z(CODE)CODE=ROMSTART-ROMEND                      #
#                            -Z(CONST)INITTAB,DATA_ID,DATA_C=ROMSTART-ROMEND   #
#                            -Z(CONST)CHECKSUM=ROMSTART-ROMEND                 #
#                            -Z(DATA)DATA_I,DATA_Z,DATA_N=RAMSTART-RAMEND      #
#                            -Z(DATA)CODE_I=RAMSTART-RAMEND                    #
#                            -Z(CONST)CODE_ID=ROMSTART-ROMEND                  #
#                            -QCODE_I=CODE_ID -D_CSTACK_SIZE=(100*10)          #
#                            -D_IRQ_STACK_SIZE=(3*8*4)                         #
#                            -Z(DATA)CSTACK+_CSTACK_SIZE=RAMSTART-RAMEND       #
#                            -Z(DATA)IRQ_STACK+_IRQ_STACK_SIZE=RAMSTART-RAMEND) #

...

                ****************************************
                *                                      *
                *            RUNTIME MODEL             *
                *                                      *
                ****************************************

  ARMv4M       = USED
  ARMv4T       = USED
  StackAlign4  = USED
  __cpu_mode   = __pcs__interwork
  __data_model = absolute
  __endian     = little
  __rt_version = 6



                ****************************************
                *                                      *
                *              MODULE MAP              *
                *                                      *
                ****************************************


  DEFINED ABSOLUTE ENTRIES
  PROGRAM MODULE, NAME : ?ABS_ENTRY_MOD

Absolute parts
           ENTRY                   ADDRESS         REF BY
           =====                   =======         ======
           _IRQ_STACK_SIZE         00000060
           _CSTACK_SIZE            00001000
           RAMEND                  00207FFF
           RAMSTART                00200000
           ROMEND                  00004000
           ROMSTART                00000000
    *************************************************************************

...

    -------------------------------------------------------------------------
CODE_I
  Relative segment, address: 002001C8 - 0020022B (0x64 bytes), align: 2
  Segment part 87.
           ENTRY                   ADDRESS         REF BY
           =====                   =======         ======
           Lock                    002001C8        Protect_Emb_Flash (flash)
    -------------------------------------------------------------------------

...

    -------------------------------------------------------------------------
CODE_ID
  Relative segment, address: 00002790 - 000027F3 (0x64 bytes), align: 2
  Segment part 110.           Intra module refs:   Lock
    -------------------------------------------------------------------------

Могу ли я быть уверенным, что код Lock() исполняется действительно из RAM? Существует ли какой-то способ прямо из тела функции проверить, из какой области памяти исполняется код?
Второй совет, насчет запрета прерываний на уровне ядра, обязательно попробую.
Go to the top of the page
 
+Quote Post
Costa
сообщение Feb 5 2009, 16:15
Сообщение #4


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 24-12-08
Пользователь №: 42 726



Сделал так (сейчас работа идет с регионом 1):

Код
__arm void Lock(void)
{
    __disable_interrupt();
  Lock2();
    __enable_interrupt();
}

__ramfunc __arm void Lock2(void)
{
   unsigned int flash_status;
    unsigned short lock_status = *AT91C_MC_FSR >> 16;
    if (lock_status & 0x2)
        return;
  *AT91C_MC_FMR = FMCN_FOR_LOCK | AT91C_MC_FWS_1FWS;
  *AT91C_MC_FCR = AT91C_MC_KEY | ((unsigned int) 1 << 12) |  AT91C_MC_FCMD_LOCK;
  do
  {
    flash_status = *AT91C_MC_FSR & AT91C_MC_EOL;
  }
  while (!flash_status);
}

Эффект нулевой, т.е. запрет прерываний на уровне ядра не помогает. Более того, вывожу на ЖКИ (есть у меня такая возможность) адреса функций Lock() и Lock2() - они совпадают с map-файлом, т.о. Lock2() действительно расположена в RAM.
Может есть какая-то логическая ошибка при работе с embedded flash? Кто работал с ней, какие там еще могут быть особенности и подводные камни? А то ситуация уже начинает напрягать sad.gif
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Feb 5 2009, 16:58
Сообщение #5


Гуру
******

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



Цитата(Costa @ Feb 5 2009, 19:15) *
Может есть какая-то логическая ошибка при работе с embedded flash? Кто работал с ней, какие там еще могут быть особенности и подводные камни? А то ситуация уже начинает напрягать sad.gif

Посотрел описание EFC SAM7A3 - душераздирающее зрелище.
Какое-то есть рассогласование со здравым смыслом:
Цитата
– 1024 pages of 256 bytes.
– 16 lock bits, each protecting 16 pages


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

Да, значение FMCN_FOR_LOCK корректно стоит?
Go to the top of the page
 
+Quote Post
Costa
сообщение Feb 5 2009, 20:51
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 24-12-08
Пользователь №: 42 726



FMCN_FOR_LOCK = 5, исходя из 48MHz MCLK. Строго говоря, оно должно быть 4.8, и у меня была мысль поэксперементировать с 4, но не успел.
А насчет программной задержки 10 мс, минуя проверку EOL - это я обязательно попробую.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Feb 5 2009, 21:40
Сообщение #7


Гуру
******

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



Цитата(Costa @ Feb 5 2009, 19:15) *
запрет прерываний на уровне ядра не помогает.

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

А не попробовали просто писать страницы?
Go to the top of the page
 
+Quote Post
Costa
сообщение Feb 6 2009, 16:13
Сообщение #8


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 24-12-08
Пользователь №: 42 726



aaarrr, спасибо за наводку!

Действительно, программа вылетала из процедуры раньше, чем нужно, а не зависала в ней, как я предполагал. Связано это с параметром FMCN_FOR_LOCK. Я измерил время, в течение которого процедура ожидает флагов, результаты такие получились:
FMCN_FOR_LOCK = 5, t = 1 ms, сбой
FMCN_FOR_LOCK = 48, t = 10 ms, норм
Примерно та же картина и при записи страниц наблюдается:
FMCN_FOR_WRITE = 72, t = 6 ms, сбой
FMCN_FOR_WRITE = 720, t = 18 ms, норм

Master Clock = 48 MHz, и почему приходится применять такие большие значения, я так и не понял. В даташите сказано:

• FMCN: Flash Microsecond Cycle Number
Before writing Lock bits, this field must be set to the number of Master Clock cycles in one hundred nanoseconds.
When writing the rest of the Flash, this field defines the number of Master Clock cycles in 1.5 microseconds. This number
must be rounded up.


В итоге, если не обращать внимания на большие значения FMCN, все работает нормально.

P.S. Про прерывания полностью согласен, так и сделал. Еще раз, большое спасибо! smile.gif
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Feb 6 2009, 16:53
Сообщение #9


Гуру
******

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



Цитата(Costa @ Feb 6 2009, 19:13) *
В итоге, если не обращать внимания на большие значения FMCN, все работает нормально.

Может, сдвинули недостаточно? Типа 10 вместо 0x10.

Upd. Нет, не похоже: FMCN при присвоении 720 будет равен 208 (8 бит), что примерно в три раза больше 72 и соответствует результатам измерений.
Go to the top of the page
 
+Quote Post

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

 


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


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