Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: AT91RM9200 после разрешения прерываний улетает на непонятные адреса
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Paramedic
Странная ситуация: отлаживал код под IAR + SAM-ICE-JTAG в SDRAM, всё было нормально. Затем сварганил загрузчик из RomBoot от Атмеля и стал загружать бинарник из датафлэш в SDRAM. И вот теперь, когда загрузчик загружает код в SDRAM и запускает его на выполнение, программа стартует всегда, но иногда (с вероятностью ~50%) программа слетает. Место слёта определил: после инициализации таймера и разрешения всех прерываний. До этого момента код работает адекватно. Никто не сталкивался с такой проблемой?
sergeeff
Значит напахано в обработчике прерываний. Показал бы, как ты его реализуешь, тогда можно чего и посоветовать.
Paramedic
Да код-то собственно, как в примере от ИАРа:

void AT91F_ST_HANDLER(void)
{
volatile int StStatus;

// Read the system timer status register
StStatus = *(AT91C_ST_SR);
StTick++;
}

void SysTmrInit (Int32U Resolution)
{
//* System Timer initialization
AT91F_ST_SetPeriodIntervalTimer(AT91C_BASE_ST,3*Resolution);
AT91F_ST_EnableIt(AT91C_BASE_ST, AT91C_ST_PITS);
AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, // AIC base address
AT91C_ID_SYS, // System peripheral ID
(AT91C_AIC_PRIOR_HIGHEST - 1),
AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE,
AT91F_ST_HANDLER );
//* Enable ST interrupt
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SYS);
}

Настраиваю на период 100мкс.
Paramedic
Не понятно почему под отладчиком ниразу не сбойнуло...
sergeeff
Да дело не в этих процедурах. Скорее всего в startup модуле прописана таблица прерываний в короткой форме, т.е. в виде branch instruction. Но это позволяет адресоваться в пределах 32 Mb.

Надо просто создать эту таблицу в виде load PC instruction:

Vector_Init_Block
LDR pc, Reset_Addr
LDR pc, Undefined_Addr
LDR pc, SVC_Addr
LDR pc, Prefetch_Addr
LDR pc, Abort_Addr
NOP ;Reserved vector
LDR pc, IRQ_Addr
LDR pc, FIQ_Addr

Reset_Addr DCD Start_Boot
Undefined_Addr DCD Undefined_Handler
SVC_Addr DCD SVC_Handler
Prefetch_Addr DCD Prefetch_Handler
Abort_Addr DCD Abort_Handler
DCD 0 ;Reserved vector
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler

Про это хорошо написано в RealView Compilation Tools Developer Guide (ARM DUI 0203G)
на сайте ARM'a.
Paramedic
Спасибо за совет, почитаю. Только не понятно почему под отладчиком работает...
Сергей Борщ
Цитата(Paramedic @ Apr 11 2007, 15:31) *
Место слёта определил: после инициализации таймера и разрешения всех прерываний.
Был в похожей ситуации. Вкратце так: загрузчик настраивает контроллер прерываний по-своему, отрабатывает, передает управление основной программе. Основная программа, надеясь на настройки контроллера прерываний по умолчанию прописывает только свои значения и разрешает прерывания. Срабатывает какое-то из непереназначенных прерываний загрузчика и программа улетает в несуществующий обработчик. Здесь может быть что-то похожее?
При старте ядро успевает выполнить несколько инструкций из флеша до того, как управление перехватит JTAG и остановит его. За это время старый код вполне мог успеть проинициализировать контроллер прерываний. Может поэтому под отладчиком и работает?
Paramedic
Цитата(sergeeff @ Apr 12 2007, 10:55) *
Да дело не в этих процедурах. Скорее всего в startup модуле прописана таблица прерываний в короткой форме, т.е. в виде branch instruction. Но это позволяет адресоваться в пределах 32 Mb.

Надо просто создать эту таблицу в виде load PC instruction:

Vector_Init_Block
LDR pc, Reset_Addr
LDR pc, Undefined_Addr
LDR pc, SVC_Addr
LDR pc, Prefetch_Addr
LDR pc, Abort_Addr
NOP ;Reserved vector
LDR pc, IRQ_Addr
LDR pc, FIQ_Addr

Reset_Addr DCD Start_Boot
Undefined_Addr DCD Undefined_Handler
SVC_Addr DCD SVC_Handler
Prefetch_Addr DCD Prefetch_Handler
Abort_Addr DCD Abort_Handler
DCD 0 ;Reserved vector
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler

Про это хорошо написано в RealView Compilation Tools Developer Guide (ARM DUI 0203G)
на сайте ARM'a.



Сделал всё по Вашей рекомендации и согласно документу - не помогло.


Цитата(Сергей Борщ @ Apr 12 2007, 11:22) *
Был в похожей ситуации. Вкратце так: загрузчик настраивает контроллер прерываний по-своему, отрабатывает, передает управление основной программе. Основная программа, надеясь на настройки контроллера прерываний по умолчанию прописывает только свои значения и разрешает прерывания. Срабатывает какое-то из непереназначенных прерываний загрузчика и программа улетает в несуществующий обработчик. Здесь может быть что-то похожее?
При старте ядро успевает выполнить несколько инструкций из флеша до того, как управление перехватит JTAG и остановит его. За это время старый код вполне мог успеть проинициализировать контроллер прерываний. Может поэтому под отладчиком и работает?



При выходе из-загрузчика там запрещаются все прерывания, а при входе в основную программу вектора переназначаются...

Вообще, попробовал написать простейший проект с мигающим светодиодом - даже с ним сложности возникли - нестабильно стартует и всё. Под дебагером работает устойчиво. Может в загрузчике где-то проблема. Не понятно в какую сторону копать...
amw
Возможно в этих двух случаях разны карты памяти.
Смотреть код и даташит на предмет REMAP.
Paramedic
Цитата(amw @ Apr 17 2007, 16:31) *
Возможно в этих двух случаях разны карты памяти.
Смотреть код и даташит на предмет REMAP.


Remap делаю, да и под отладчиком-то всё работает.

А кто-нибудь вообще атмеловкий RomBoot использовал? Не было проблем?
sergeeff
Можно до разрешения прерываний распечатать таблицу прерываний с адреса 0х000000000 и посмотреть, что-же там реально прописано.
amw
Цитата(Paramedic @ Apr 17 2007, 15:57) *
Remap делаю, да и под отладчиком-то всё работает.

А кто-нибудь вообще атмеловкий RomBoot использовал? Не было проблем?

Кроме самого remap нужно еще убедится, что смещения в командах Exception vectors правильны.
Возможно это поможет http://electronix.ru/forum/index.php?showtopic=25634
Paramedic
Цитата(sergeeff @ Apr 17 2007, 17:05) *
Можно до разрешения прерываний распечатать таблицу прерываний с адреса 0х000000000 и посмотреть, что-же там реально прописано.


Делал. В сбойном и не сбойном случае одно и тоже. Даже CRC кода считал - тоже не меняется...
amw
Цитата(Paramedic @ Apr 17 2007, 16:08) *
Делал. В сбойном и не сбойном случае одно и тоже. Даже CRC кода считал - тоже не меняется...

А таблица ссылается на правильные адреса обработчиков?
Paramedic
Цитата(amw @ Apr 17 2007, 17:13) *
А таблица ссылается на правильные адреса обработчиков?


Да, тем более иногда-то запускается...
Paramedic
Всем большое спасибо за советы, вроде решил проблему.
Закоментировал участок стартапа загрузчика:
/*----------------------------------------
Read/modify/write CP15 control register
----------------------------------------*/
mrc p15, 0, r0, c1, c0,0 /* read cp15 control registre (cp15 r1) in r0 */
ldr r3,= 0xC0000080 /* Reset bit :Little Endian end fast bus mode */
ldr r4,= 0xC0001000 /* Set bit :Asynchronous clock mode, Not Fast Bus, I-Cache enable */
bic r0, r0, r3
orr r0, r0, r4
mcr p15, 0, r0, c1, c0,0 /* write r0 in cp15 control registre (cp15 r1) */

то есть похоже что кэш инструкций мешал при переходе от бутлоадера к основной программе.

И ещё в библиотеке lib_AT91RM9200.h вроде ошибка (помечена /*!!!!!!!!!!!!!!!!!!*/):

inline void AT91F_AIC_Open(
AT91PS_AIC pAic, // \arg pointer to the AIC registers
void (*IrqHandler) (), // \arg Default IRQ vector exception
void (*FiqHandler) (), // \arg Default FIQ vector exception
void (*DefaultHandler) (), // \arg Default Handler set in ISR
void (*SpuriousHandler) (), // \arg Default Spurious Handler
unsigned int protectMode) // \arg Debug Control Register
{
int i;

// Disable all interrupts and set IVR to the default handler
for (i = 0; i < 32; ++i) {
AT91F_AIC_DisableIt(pAic, i);
AT91F_AIC_ConfigureIt(pAic, i, AT91C_AIC_PRIOR_LOWEST, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, DefaultHandler);
}

// Set the IRQ exception vector
AT91F_AIC_SetExceptionVector((unsigned int *) 0x18/*!!!!!!!!!!!!!!!!!!*/, IrqHandler);
// Set the Fast Interrupt exception vector
AT91F_AIC_SetExceptionVector((unsigned int *) 0x1C/*!!!!!!!!!!!!!!!!!!*/, FiqHandler);

pAic->AIC_SPU = (unsigned int) SpuriousHandler;
pAic->AIC_DCR = protectMode;
}

inline unsigned int AT91F_AIC_SetExceptionVector (
unsigned int *pVector, // \arg pointer to the AIC registers
void (*Handler) () ) // \arg Interrupt Handler
{
unsigned int oldVector = *pVector;

if ((unsigned int) Handler == (unsigned int) AT91C_AIC_BRANCH_OPCODE)
*pVector = (unsigned int) AT91C_AIC_BRANCH_OPCODE;
else
*pVector = (((((unsigned int) Handler) - ((unsigned int) pVector) - 0x8) >> 2) & 0x00FFFFFF) | 0xEA000000;

return oldVector;
}

0x18 и 0x1C никак не "pointer to the AIC registers".
sergeeff
Ну добрались таки до самого интересного. Стандартная функция AT91F_AIC_SetExceptionVector прописывает правильный handler обработчика прерывания только!!! для "короткой" таблицы прерываний. В твоем случае должна использоваться "длинная" таблица, т.к. вектора прерываний лежат с адреса 0х00000000, а программа твоя стартует из SDRAM с адресов 0х20000000. Поэтому я написал для этого варианта функцию:

void SetExceptionVector(unsigned int *IrqVec, void (*Handler)(void))
{
DWORD *pbHandler;

switch ((int)IrqVec)
{
case 0x0C:
case 0x10:
case 0x04:
pbHandler = (DWORD *)(0x20 + (int)IrqVec);
*pbHandler = (DWORD)Handler;
break;
default:
break;
}
}
Ну и надо самому нормально инициализиривать AIC и не пользоваться стандартной AT91F_AIC_Open.

А насчет i-cache - это, похоже, вторичный эффект.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.