|
|
  |
Зависание при попытке записи во Flash |
|
|
|
Feb 8 2011, 20:43
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 2-10-10
Пользователь №: 59 884

|
Вновь обращаюсь к вам с просьбой о помощи! Использую компилятор WinARM, процессор - AT91SAM7S256. Есть функция записи во флеш: CODE //******************************************************************************** ****** // Тут у нас все что касается записи во флеш //******************************************************************************** ******
extern void AT91F_Enable_Interrupt(void); extern void AT91F_Disable_Interrupt(void);
#define RAMFUNC __attribute__ ((section (".ram_func")))
#define EFC_PAGE_SIZE 256 #define EFC_PAGE_COUNT 1024 #define EFC_PagesInTheLockRegion 64 #define EFC_PAGE_SIZE_UINT (EFC_PAGE_SIZE/4) // Количество unsigned int
unsigned long int RAMFUNC EFC_WritePage(unsigned long int adr, unsigned long int *pbuf) { unsigned int *pflash; unsigned int page; unsigned int region; unsigned int i;
pflash = (unsigned int *)adr; page = (adr & 0x3FFFF)/EFC_PAGE_SIZE; region = (page/EFC_PagesInTheLockRegion);
//Init while (!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY)) ; AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(100 <<16)) | AT91C_MC_FWS_1FWS ; while (!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY)) ; if (AT91C_BASE_MC->MC_FSR & (region << 16)) { // lock set, clear it AT91C_BASE_MC->MC_FMR = ((AT91C_MC_FMCN)&(50 <<16)) | AT91C_MC_FWS_2FWS ; AT91C_BASE_MC->MC_FCR = (0x5A << 24) | (region << 8 ) |AT91C_MC_FCMD_UNLOCK; //!!!проблемное место!!! } while (!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY)) ; for (i = 0; i < EFC_PAGE_SIZE_UINT; i++) *(pflash + i ) = *(pbuf + i); //!!!проблемное место!!! AT91F_PIO_SetOutput( AT91C_BASE_PIOA, 0x400 ) ; AT91C_BASE_MC->MC_FCR = (0x5A << 24) | (page << 8 ) |AT91C_MC_FCMD_START_PROG; //!!!проблемное место!!! while (!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY)) ;
return 1; }
void RAMFUNC EFCWrite(unsigned long int adr, unsigned char *pbuf, unsigned long int Len, unsigned long int NeedReset) { unsigned long int l; if (NeedReset) { l=0; } l=0; while (l<Len) { EFC_WritePage(adr, (unsigned long int*)&(pbuf[l])); l+=EFC_PAGE_SIZE; adr+=EFC_PAGE_SIZE; } if (NeedReset) { __asm("sub r0, r0,r0;"); __asm("bx r0;"); } }
//******************************************************************************** ******
В основной функции пишу: Код unsigned int buf1[1]; #define Tester 0x110001 buf1[1] = 1; AT91F_Disable_Interrupt(); EFCWrite(Tester,(unsigned char*)buf1,4,0); AT91F_Enable_Interrupt(); Т.е. прерывания перед записью я отключаю, у функции записи прописал атрибут вызова из RAM... Но при любом обращении ко флеш (в коде пометил как "проблемные места") процессор зависает. В чем может быть причина?
|
|
|
|
|
Feb 10 2011, 20:23
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 2-10-10
Пользователь №: 59 884

|
Я видимо в Linker-script не описал область для ram_func. Нашел на заморском сайте: Цитата Also, in your linker map you need to indicate where .ramsection resides:
.data : AT (_etext) { _data =3D . ; KEEP(*(.vectram)) /* added by mthomas */=09 *(.data) SORT(CONSTRUCTORS) . =3D ALIGN(4); *(.ramsection) /* here your ramsection will be located */ } >DATA . =3D ALIGN(4); Компилятор, как водится, сначала ругался на 3D ALIGN(4). Убрал слово 3D и компилятор стал выдавать "cannot find _data". В общем, я не понял что они имели ввиду. Прописал следующим образом: Код MEMORY { FLASH (r) : ORIGIN = 0x00100000, LENGTH = 0x00040000 DATA (rw) : ORIGIN = 0x00200000, LENGTH = 0x00010000 STACK (rw) : ORIGIN = 0x00210000, LENGTH = 0x00000000 }
...
.data : AT (_etext) { _data = .; *(.data) SORT(CONSTRUCTORS) *(.ramfunc) } >DATA . = ALIGN(4);
_edata = .; PROVIDE (edata = .); main.map мне сообщает: Код *(.ramfunc) .ramfunc 0x00200008 0x14 main.o 0x00200008 EFC_WritePage Т.е. вроде бы функция находится в ram, но программа все-равно зависает после записи. Но если переподключить устройство, то окажется что во флеш все успешно записалось. Меня смущает тег FLASH ( r ) (т.е. только чтение) в блоке MEMORY. Но если поставить rw, то компилятор пишет про какой-то overlap между секциями... Поможите с советом!
Сообщение отредактировал mr.smart - Feb 10 2011, 22:22
|
|
|
|
|
Feb 11 2011, 07:52
|

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

|
QUOTE (mr.smart @ Feb 10 2011, 22:23)  CODE .data : AT (_etext) { _data = .; *(.data) SORT(CONSTRUCTORS) *(.ramfunc) } >DATA . = ALIGN(4); 1) Зачем конструкторы засовывать в ОЗУ? 2) входные секции лучше указывать как *(.data*), *(.ramfunc*) и т.д. - это позволит вам корректно линковать код, скомпилированный с опциями -ffunction-sections, -fdata-sections. 3) Какая у вас частота ядра? Правильно ли вы рассчитываете константу FMCN? 4) Почему вы пишите то AT91C_MC_FWS_1FWS то AT91C_MC_FWS_2FWS? 5) Переход на адрес 0 - это совсем не reset. Рекомендую собаку. 6) А запрещаете ли вы прерывания? Выкиньте из проекта все лишнее, запакуйте в zip и прикрепите к сообщению - посмотрим. Не нравится мне ваш скрипт в части .data : AT (_etext). вот что у меня: CODE ENTRY(_start) IRQ_STACK_SIZE = 0x100; SYS_STACK_SIZE = 0x1800;
/* memory layout */ MEMORY { VECTORS (rx) : ORIGIN = 0x00100000, LENGTH = 0x40 ROM (rx) : ORIGIN = 0x00100040, LENGTH = 0x00001000 - 0x40 RAM (rwx) : ORIGIN = 0x00200000, LENGTH = 0x00004000 REMAPPED (rwx) : ORIGIN = 0x00000000, LENGTH = LENGTH(RAM) }
SECTIONS { .vectors : { KEEP(*(.vectors)) } > REMAPPED AT > VECTORS
.text : { __ctors_start = .; KEEP(SORT(*)(.ctors)) KEEP(SORT(*)(.init_array)) __ctors_end = .; __dtors_start = .; KEEP(SORT(*)(.dtors)) __dtors_end = .;
. = ALIGN(4);
*(.text*) /* code */
*(.rodata) /* read-only data (constants) */ *(.rodata*)
*(.glue_7) *(.glue_7t) } > ROM
. = ALIGN(4); _etext = .;
/* .data section which is used for initialized data */ .data : /* place init values immediatly after .text section */ { _data = .; *(.ramfunc*) *(.data*)
PROVIDE (_edata = .); _data_image = LOADADDR(.data);
} > RAM AT > ROM
/* .bss section which is used for uninitialized data */ .bss: (NOLOAD) : { . = ALIGN(4); __bss_start = . ; __bss_start__ = . ; *(.bss*) *(COMMON) . = ALIGN(4); PROVIDE (__bss_end = .); } > RAM
.noinit (NOLOAD) : { . = ALIGN(4); PROVIDE (__noinit_start = .) ; *(.noinit*) PROVIDE (__noinit_end = .) ; PROVIDE (__heap_start = .) ; } > RAM
.stack : { . = ALIGN(4); . += SYS_STACK_SIZE; PROVIDE (__stack = .); . += IRQ_STACK_SIZE; PROVIDE (__stack_irq = .); /* allocate stacks if needed */ PROVIDE (__stack_fiq = .); PROVIDE (__stack_und = .); PROVIDE (__stack_abort = .); PROVIDE (__stack_svc = .); } > RAM
_end = . ; PROVIDE (end = .);
/* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } P.S. Вообще-то в озу достаточно расположить только команду записи в AT91C_BASE_MC->MC_FCR и цикл ожидания AT91C_MC_FRDY.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 11 2011, 20:03
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 2-10-10
Пользователь №: 59 884

|
Сергей Борщ, ОГРОМНОЕ спасибо за советы и за Ваш линкер-скрипт. Буду разбираться с ним. По поводу моей проблемы: я изменил функцию записи во флеш на ту, которую предлагали Вы в многочисленных аналогичных обсуждениях, ибо она прекрасна: Код #define RAMFUNC __attribute__ ((section (".ramfunc")))
void RAMFUNC FlashTest_RAM(uint32_t command) { AT91C_BASE_MC->MC_FCR = command; //AT91C_BASE_PIOA->PIO_SODR = 0x400; // Тут необъяснимое явление. Кстати 0х400 - это 10ый PIO, к нему подключен светодиод. while(!(AT91C_BASE_MC->MC_FSR & AT91C_MC_FRDY)); }
void FlashTest(uint32_t command, uint32_t mode) { AT91F_Disable_Interrupt(); AT91C_BASE_MC->MC_FMR = mode; FlashTest_RAM(command); AT91F_Enable_Interrupt(); }
#define MCK_CYCLES ((15ULL * MCK + 5000000) / 10000000) #define FLASH_WAITSTATES MCK_CYCLES < 30000000ULL ? AT91C_MC_FWS_0FWS : AT91C_MC_FWS_1FWS
inline void RewritePage(uint32_t const *addr) { FlashTest( (0x5AULL * AT91C_MC_KEY / 0xFF) | (((uint32_t)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) | (MCK_CYCLES * AT91C_MC_FMCN / 0xFF)); } Процессор точно так же зависал, НО!!! Если разкоментировать строчку AT91C_BASE_PIOA->PIO_SODR = 0x400, которую я пометил как "необъяснимое явление", то все прекрасно работает!!! Т.е. если зажечь в этом месте светодиод, то все работает!!! Вопрос - Как так-то?! Кстати пользуясь случаем, хочу задать Вам вопрос по функции записи, а вернее по данному элементу: (((uint32_t)addr >> 7) << 8). Зачем смещать на 7? Я этого никак понять не могу... И какой в этом случае формат адреса страницы addr? Я изменил на ((uint32_t)addr << 8) и когда, например, обращаюсь к 512ой странице, присваиваю addr = 0x200. Работает и это меня не удивляет.
|
|
|
|
|
Feb 12 2011, 13:34
|

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

|
QUOTE (mr.smart @ Feb 11 2011, 22:03)  Процессор точно так же зависал, НО!!! Если разкоментировать строчку AT91C_BASE_PIOA->PIO_SODR = 0x400, которую я пометил как "необъяснимое явление", то все прекрасно работает!!! Т.е. если зажечь в этом месте светодиод, то все работает!!! Вопрос - Как так-то?! А что делает магическая функция AT91F_Disable_Interrupt()? Возможно она запрещает только IRQ, а у вас еще задействовано FIQ? Даже и не знаю, что еще можно придумать. Проблема пропадает именно при включении светодиода, или при любом действии с портом? С питанием все в порядке? Земли на все ноги заведены, питание на VDDFLASH заведено и зашунтировано блокировочным конденсатором? QUOTE (mr.smart @ Feb 11 2011, 22:03)  по данному элементу: (((uint32_t)addr >> 7) << 8). Зачем смещать на 7? Я этого никак понять не могу... И какой в этом случае формат адреса страницы addr? Это писалось для SAM7S64, у него страница 128 байт. У вас страница 256 байт, надо писать (((uint32_t)addr >> 8) << 8). Я оставляю оба сдвига чтобы был виден смысл этого действия - сначала addr >> 8 - из адреса байта получаем номер страницы, потом этот номер сдвигаем на свое место: << 8. Если вы передаете в функцию сразу номер страницы, то один сдвиг пропадает. Мне удобнее было передавать адрес любой ячейки внутри страницы.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 12 2011, 17:37
|

Участник

Группа: Участник
Сообщений: 28
Регистрация: 2-10-10
Пользователь №: 59 884

|
Цитата А что делает магическая функция AT91F_Disable_Interrupt()? Возможно она запрещает только IRQ, а у вас еще задействовано FIQ? Даже и не знаю, что еще можно придумать. Проблема пропадает именно при включении светодиода, или при любом действии с портом? С питанием все в порядке? Земли на все ноги заведены, питание на VDDFLASH заведено и зашунтировано блокировочным конденсатором? Код AT91F_Disable_Interrupt() : Код #define I_BIT 0x00000080 #define F_BIT 0x00000040
mrs r0,CPSR orr r0, r0, #(I_BIT | F_BIT) msr CPSR_c,r0 mrs r0,CPSR ands r0,r0, #(I_BIT | F_BIT) beq AT91F_Disable_Interrupt bx lr Т.е. FIQ вроде как тоже запрещается. С землей все в порядке, блокировочный конденсатор на месте. После нескольких экспериментов оказалось, что проблема пропадает не только если зажечь светодиод, но и вообще после любого действия с любым PIO! Да даже запись в регистр RTMR помогает! Теоретически... Возможно действительно что-то с питанием от USB... Ибо здесь у меня тоже были проблемы с зависанием при ожидании бита подтверждения, и был сделан вывод о несовершенстве моего USB-порта. Но только в данном-то случае по юсб ничего не передается, а бит подтверждения FRDY генерируется внутри процессора... Чуть позже попробую испытать на другом компьютере... Может с ним все нормально будет...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|