|
Проблемы при работе со встроенной flash, AT91SAM7A3, bootloader |
|
|
|
Feb 4 2009, 17:34
|
Участник

Группа: Участник
Сообщений: 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 прописан, и соотв. библиотека к проекту подключена... Помогите разобраться, где накосячил.
|
|
|
|
|
 |
Ответов
(1 - 8)
|
Feb 5 2009, 06:44
|
Участник

Группа: Участник
Сообщений: 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? Существует ли какой-то способ прямо из тела функции проверить, из какой области памяти исполняется код? Второй совет, насчет запрета прерываний на уровне ядра, обязательно попробую.
|
|
|
|
|
Feb 5 2009, 16:15
|
Участник

Группа: Участник
Сообщений: 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? Кто работал с ней, какие там еще могут быть особенности и подводные камни? А то ситуация уже начинает напрягать
|
|
|
|
|
Feb 5 2009, 16:58
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(Costa @ Feb 5 2009, 19:15)  Может есть какая-то логическая ошибка при работе с embedded flash? Кто работал с ней, какие там еще могут быть особенности и подводные камни? А то ситуация уже начинает напрягать  Посотрел описание EFC SAM7A3 - душераздирающее зрелище. Какое-то есть рассогласование со здравым смыслом: Цитата – 1024 pages of 256 bytes. – 16 lock bits, each protecting 16 pages Есть у меня ощущение, что программа вылетает моментально на проверке EOL и, естественно, наворачивается. На счетчике, упомянутом в первом посте, может быть такая же картина, если он слишком быстро считает. Попробуйте сделать достаточно долгую (10мс) программную задержку перед выходом из процедуры. Да, значение FMCN_FOR_LOCK корректно стоит?
|
|
|
|
|
Feb 5 2009, 20:51
|
Участник

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

|
FMCN_FOR_LOCK = 5, исходя из 48MHz MCLK. Строго говоря, оно должно быть 4.8, и у меня была мысль поэксперементировать с 4, но не успел. А насчет программной задержки 10 мс, минуя проверку EOL - это я обязательно попробую.
|
|
|
|
|
Feb 6 2009, 16:13
|
Участник

Группа: Участник
Сообщений: 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. Про прерывания полностью согласен, так и сделал. Еще раз, большое спасибо!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|