Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Проблема с IRQ прерыванием
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Daermon
Проект под IAR 4.41
Язык С/С++

Программа сделана для работы с внешнего ОЗУ 0х21000000
Вектора прописываются там же 0х21000000
Появиласть проблема с IRQ прерыванием... так как нужно послать PC по адресу 0хfffff100 где расположен AIC_SVR. Но при срабатывании прерывания попадаем по адрессу 0х00000018.

Как мне быть есть два пути:
1 - разместить вектора по адр 0х00000018
2 - добится того чтобы ldr pc, [pc,#-0xF20] посылала на 0xfffff100,
но тогда необходимо прибавить к PC,#0xdefff0e8 , синтаксис не позволяет мне этого сделать.

Может есть еще какие решения?

from startup code
;---------------------------------------------------------------
; ?RESET
; Reset Vector.
; Normally, segment INTVEC is linked at address 0.
; For debugging purposes, INTVEC may be placed at other
; addresses.
; A debugger that honors the entry point will start the
; program in a normal way even if INTVEC is not at address 0.
;---------------------------------------------------------------
MODULE ?RESET
; COMMON INTVEC:CODE:NOROOT(2);
RSEG ICODE:CODE:NOROOT(2)
PUBLIC __program_start
EXTERN ?cstartup
; EXTERN undef_handler, swi_handler, prefetch_handler
; EXTERN data_handler, irq_handler, fiq_handler
CODE32; Always ARM mode after reset
ADRSTART:
org 0x00+ADRSTART
__program_start
ldr pc,=?cstartup; Absolute jump
org 0x04+ADRSTART
undef_handler:
ldr pc,=undef_handler
org 0x08+ADRSTART
swi_handler:
ldr pc,=swi_handler
org 0x0c+ADRSTART
prefetch_handler:
ldr pc,=prefetch_handler
org 0x10+ADRSTART
data_handler:
ldr pc,=data_handler
org 0x18+ADRSTART
ldr pc, [pc,#-0xF20] ; IRQ : read the AIC
org 0x1c+ADRSTART
fiq_handler:
ldr pc,=fiq_handler

; Constant table entries (for ldr pc) will be placed at 0x20
org 0x20+ADRSTART
LTORG
; ENDMOD __program_start
ENDMOD
alexander55
Цитата(Daermon @ Oct 30 2007, 14:06) *

Рекомендую указать компилятор и uC для определенности.
Сергей Борщ
Цитата(Daermon @ Oct 30 2007, 14:06) *
Программа сделана для работы с внешнего ОЗУ 0х21000000
Вектора прописываются там же 0х21000000
Вы можете разместить вектора где угодно, но процессор, несмотря на это, все равно будет при исключениях переходить в фиксированные адреса 00-1С. Поэтому, при размещении векторов в ОЗУ надо сделать remap, тогда начальная область ОЗУ (или все ОЗУ) окажется также отражено на нулевые адреса и процессор при исключении попадет на ваши вектора. Только надо помпить, что несмотря на то, что вектора физически расположены в верхних адресах, их содержимое должно быть таким, как будто они находятся в нулевых. В вашем случае надо написть в .xcl что-то вроде
Код
-DRAMSTART=21000000
-DRAMEND=21003FFF

// vectors always linked to 0x00-0x3F
-Z(CODE)INTVEC=00000000-0000003F

// Mirrored vectors placed in RAM
-Z(CODE)INTVEC_I=RAMSTART-RAMEND
-QINTVEC=INTVEC_I

-Z(CODE)ICODE,CODE,DIFUNCT,SWITAB=RAMSTART-RAMEND
А при старте отладчика (в .mac) сделать ремап :
Код
execUserReset()
{
    Remap_RAM();
    __writeMemory32(0xD3,0x98,"Register");                          // CPSR = SVC mode, ARM, IRQ, FIQ disabled
    __writeMemory32(0x00000000,0xB4,"Register");
}

Remap_RAM()
{
    __var tmp;
    tmp = __readMemory32(0x00200000, "Memory");                     // read from RAM area
    __writeMemory32(~tmp, 0x00200000, "Memory");                    // alter RAM area
    if( ~tmp != __readMemory32(0x00000000, "Memory") )              // check if altering mirrored to remap area
    {
        __writeMemory32(0x00000001, 0xFFFFFF00,"Memory");            // otherwice remap
    }
    __writeMemory32(tmp, 0x00200000 ,"Memory");                     // restore RAM data
    __message " remapped to RAM";
}



Цитата(alexander55 @ Oct 30 2007, 14:12) *
Рекомендую указать компилятор и uC для определенности.
Компилятор был указан, а насчет uC - прекрасный повод потренироваться в телепатии. Раз упомятут AIC_SVR - это атмел. Раз ОЗУ живет начиная с 0x21000000 - это что-нибудь с внешней памятью. Интуитивно предполагаем RM9200.
Daermon
Спасибо большое!
Но у меня пара вопросов появилась.

Исправления в .xlc
Добавил:
-DRAMSTART=21000000
-DRAMEND=22000000
вместо:
//-DRAMSTART=(MEMSTART+40)
//-DRAMEND=MEMEND
//******************************************

//************************************************
// Address range for reset and exception
// vectors (INTVEC).
// The vector area is 32 bytes,
// an additional 32 bytes is allocated for the
// constant table used by ldr PC in cstartup.s79.
//************************************************
Добавил:
// vectors always linked to 0x00-0x3F
-Z(CODE)INTVEC=00000000-0000003F
// Mirrored vectors placed in RAM
-Z(CODE)INTVEC_I=RAMSTART-RAMEND
-QINTVEC=INTVEC_I
Было:
//-Z(CODE)INTVEC=MEMSTART:+40

//***************************************************
Тоже добавил:
-Z(CODE)ICODE,CODE,DIFUNCT,SWITAB=RAMSTART-RAMEND

//////////////////////////////////////////////////////////////////////////////////

Remap_RAM()
{
__var tmp;
tmp = __readMemory32(0x00200000, "Memory"); // read from RAM area

__writeMemory32(~tmp, 0x00200000, "Memory"); // alter RAM area
if( ~tmp != __readMemory32(0x00000000, "Memory") ) // check if altering mirrored to remap area
{
__writeMemory32(0x00000001, 0xFFFFFF00,"Memory"); // otherwice remap
}
__writeMemory32(tmp, 0x00200000 ,"Memory"); // restore RAM data
__message " remapped to RAM";
}
Это все тоже добавил, но не совсем понятно что именно происходит тут?



Вот что добавил в *.mac

execUserPreload()
{
init_PLL_180();
//__writeMemory32(0xAAAAAAAA,0x00000000,"Memory");
// if(__readMemory32(0x00000000,"Memory") != 0xAAAAAAAA)
// {
// __writeMemory32(0x01,0xFFFFFF00,"Memory"); // MC_RCR: toggle remap bit
// }

init_SDRAM ();
Remap_RAM();
// __writeMemory32(0xD3,0x98,"Register"); // CPSR = SVC mode, ARM, IRQ, FIQ disabled
// __writeMemory32(0x00000000,0xB4,"Register");

__message("Target init macro complete");

Где то что то не так, потому что копирование векторов не происходит.[size=4]



}
Сергей Борщ
Цитата(Daermon @ Oct 30 2007, 16:38) *
Это все тоже добавил, но не совсем понятно что именно происходит тут?
Упс, виноват - это был ремап на внутреннее ОЗУ для SAM7S. Поскольку вы так и не уточнили, что у вас за контроллер, будет трудновато подсказать. Но идея Remap_RAM() все та же: считываем из ОЗУ из области, где лежат вектора значение, запоминаем его, изменяем эту ячейку в ОЗУ, смотрим, отразилось ли это изменение на области векторов. Если отразилось - ремап уже сделан, если не отразилось - делаем ремап. После чего восстанавливаем считанное в начале значение. Если у вас RM9200, то он не умеет ремапить SDRAM на нулевые адреса. Вам придется скопировать вектора в начало внутреннего ОЗУ и после этого сделать Remap на внутреннее ОЗУ:
Код
execUserPreload()
{
    __var i;
    init_PLL_180();
    init_SDRAM ();
}
execUserReset()
{
    for( i = 0; i < 0x40; i += 4 )                      // copy vectors from app to internal RAM
    {
        tmp = __readMemory32(0x21000000 + i, "Memory");
        __writeMemory32(tmp,0x00200000 + i, "Memory");
    }

    Remap_RAM();


    __writeMemory32(0xD3,0x98,"Register");                          // CPSR = SVC mode, ARM, IRQ, FIQ disabled
    __writeMemory32(0x00000000,0xB4,"Register");
}
Причем копирование надо делать в execUserReset() или execUserSetup(), потому что в момент исполнения execUserPreload() ваша программа еще не загружена и копировать нечего. Или можно обойтись без копирования, если сразу слинковать вектора во внутреннее ОЗУ:
Код
-DINTRAMSTART=00200000
-DINTRAMEND=00203FFF

// vectors always linked to 0x00-0x3F
-Z(CODE)INTVEC=00000000-0000003F

// Mirrored vectors placed in internal RAM
-Z(CODE)INTVEC_I=INTRAMSTART-INTRAMEND
-QINTVEC=INTVEC_I
Daermon
Каша в голове smile.gif

Попробую по порядку:

1. sturtup код настраивает вектора прерывания на адрес 0х21000000

2. мне необходимо сделать зеркало с адреса 0х21000000 на 0х00000000
// vectors always linked to 0x00-0x3F
-Z(CODE)INTVEC=00000000-0000003F
// Mirrored vectors placed in RAM
-Z(CODE)INTVEC_I=RAMSTART-RAMEND
-QINTVEC=INTVEC_I // Вот тут буква Q обязательна?

3. В файл *.mac добавить
execUserReset()
{
for( i = 0; i < 0x40; i += 4 ) // copy vectors from app to internal RAM
{
tmp = __readMemory32(0x21000000 + i, "Memory");
__writeMemory32(tmp,0x00200000 + i, "Memory"); // Здесь точно 0x00200000? и почему он? а не например 0x00000000.
}



// делаем ремап
__var tmp;
tmp = __readMemory32(0x00200000, "Memory"); // read from RAM area
__writeMemory32(~tmp, 0x00200000, "Memory"); // alter RAM area
if( ~tmp != __readMemory32(0x00000000, "Memory") ) // check if altering mirrored to remap area
{
__writeMemory32(0x00000001, 0xFFFFFF00,"Memory"); // otherwice remap
}
__writeMemory32(tmp, 0x00200000 ,"Memory"); // restore RAM data
__message " remapped to RAM";




__writeMemory32(0xD3,0x98,"Register"); // CPSR = SVC mode, ARM, IRQ, FIQ disabled
__writeMemory32(0x00000000,0xB4,"Register");
}



4. Хотел узнать когда именно исполняется execUserReset() и execUserPreload() до стартапа или после него?


Почему то после всего что сделал полностью затирается облатсть 0х00000000 - 0х001ffffc
Daermon
Все... из внутреннего ОЗУ (0x00200000) все ремапится в 0х00000000

Но вот из внешнего ОЗУ 0x21000000 не копируются данные во внутреннее ОЗУ.

execUserSetup()
{

__var tmp;
for( i = 0; i < 0x40; i += 4 ) // copy vectors from app to internal RAM
{
tmp = __readMemory32(0x21000000 + i, "Memory"); // НЕ РАБОТАЕТ!!!
__writeMemory32(tmp,0x00200000+ i, "Memory");
}
Remap_RAM();

//__writeMemory32(0xD3,0x98,"Register"); // CPSR = SVC mode, ARM, IRQ, FIQ disabled
//__writeMemory32(0x00000000,0xB4,"Register");
}
Daermon
Вроде бы в этом разобрался, но появилась другая проблема.
Теперь программа начала стартовать с адресса 0х00000000, что не есть ГУД.

Помагает программный Reset, после которого прогрмма стартует с адресса 0x21000000 и прерывания срабатывают нормально.

execUserPreload()
{
init_PLL_180();
init_SDRAM ();
__message("Target init macro complete");
}
execUserSetup()
{
__var tmp,i;
Remap_RAM();
for( i = 0; i < 0x40; i += 4 ) // copy vectors from app to internal RAM
{
tmp = __readMemory32(0x21000000 + i, "Memory");
__writeMemory32(tmp,0x00200000+ i, "Memory");
}
__writeMemory32(0xD3,0x98,"Register"); // CPSR = SVC mode, ARM, IRQ, FIQ disabled
__writeMemory32(0x00000000,0xB4,"Register");
}


в .xlc

//************************************************
// Address range for reset and exception
// vectors (INTVEC).
// The vector area is 32 bytes,
// an additional 32 bytes is allocated for the
// constant table used by ldr PC in cstartup.s79.
//************************************************
-Z(CODE)INTVEC=0x00000000-0x0000003F
-Z(CODE)INTVEC_I=0x21000000-0x2100003f
-QINTVEC_I=INTVEC



Что сделать чтобы программа стартовала с адресса 0х21000000???
Сергей Борщ
Цитата(Daermon @ Oct 31 2007, 13:25) *
Теперь программа начала стартовать с адресса 0х00000000, что не есть ГУД.
Что сделать чтобы программа стартовала с адресса 0х21000000???
Почему не есть гуд? Ведь именно с этого адреса программа стартует в железе без отладчика. По адресу 0х21000000 располагается вектор ресета, который вы скопировали во внутреннее ОЗУ и отмапировали на адрес 0. Т.е. старт с адреса 0 должен приводить к тому же результату. Но если хотите - в execUserReset в конец допишите
Код
__writeMemory32(0xD3,0x98,"Register"); // CPSR = SVC mode, ARM, IRQ, FIQ disabled
__writeMemory32(0x21000000,0xB4,"Register");

Цитата(Daermon @ Oct 31 2007, 08:53) *
-QINTVEC=INTVEC_I // Вот тут буква Q обязательна?
Help->Linker and library tools user guide.
Цитата(Daermon @ Oct 31 2007, 08:53) *
4. Хотел узнать когда именно исполняется execUserReset() и execUserPreload() до стартапа или после него?
Посмотрите Help->ARM Embedded Workbench User guide. Поищите по ключевому слову execUserPreload - там все довольно подробно описано.

Мне тут пришел в голову еще один вариант, как обойтись без копирования - сделать ремап в execUserPreload(), а вектора расположить по адресу 0. Тогда при загрузке по адресу 0 будет внутреннее ОЗУ и вектора сразу лягут куда надо.
Daermon
Спасибо.
Наконец прерывания заработали....но только при работе через SAM-ICE. После того как заливаю во внешнюю ОЗУ, при возникновении прерывания программа зависает.


Запускаю плату:
U-Boot 1.1.4 (Aug 20 2006 - 21:33:18)

DRAM: 32 MB
Parallel flash ignored
Flash: 0 kB
DataFlash:AT45DB642
Nb pages: 8192
Page Size: 1056
Size= 8650752 bytes
Logical address: 0xC0000000
Area 0: C0000000 to C00083FF (RO) Bootstrap
Area 1: C0008400 to C003DDFF (RO) U-Boot
Area 3: C003FF00 to C0041FFF Environment
Area 4: C0042000 to C018BFFF OS
Area 5: C018C000 to C083FFFF FS
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
U-Boot>


Закачиваю через DBGU файл - формат raw-binary:
U-Boot> loadb
## Ready for binary (kermit) download to 0x21000000 at 115200 bps...
## Total Size = 0x0000316c = 12652 Bytes
## Start Addr = 0x21000000
U-Boot>go 0x21000000


И вот тут при появлении прерывания программа зависает...

Что тут может быть?
Сергей Борщ
Цитата(Daermon @ Oct 31 2007, 14:40) *
U-Boot>go 0x21000000
И вот тут при появлении прерывания программа зависает...
Видимо все то же - никто не скопировал вектора, никто не сделал Remap.Могу предложить добавить в программу функцию
Код
#include <stdint.h>
_C_LIB_DECL
#pragma language=extended
#pragma location="ICODE"
int __low_level_init(void)
{
    // copy vectors
    uint32_t const *pSrc = (uint32_t *)0x21000000;
    uint32_t *pDst = (uint32_t *)0x00200000; //RAMSTART
    uint_fast8_t Size = 0x40 / sizeof *Dst;
    do { *pDst++ = *pSrc++; } while (--Size);

    // remap
    uint32_t *pVectors = (uint32_t *)0x00200014; //reserved vector in mirrored RAM
    uint32_t Tmp = *pVectors;
    *pVectors = ~Tmp;
    if( (uint32_t *)0x00000014 != ~Tmp )
        AT91C_BASE_MC->MC_RCR = AT91C_MC_RCB;    // REMAP
    *pVectors = Tmp;

    return 1; // init RAM.
}
#pragma language=default
_END_C_LIB_DECL
Daermon
Чуть подправил
if( *((uint32_t *)0x00000014) != ~Tmp )

И все !!! Работает!!
Огромное СПАСИБА!!!
zltigo
Цитата(Daermon @ Oct 31 2007, 15:35) *
if( *((uint32_t *)0x00000014) != ~Tmp )

Совсем лишние скобки глаз режут:

if( *(uint32_t *)0x00000014 != ~Tmp )
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.