Перейти к содержанию
    

AT91SAM9XE512 - не работают прерывания

Доброго времени суток!

 

Не работают прерывания на AT91SAM9XE512 - ни по таймеру, ни по USART.

 

Инициализация проходит нормально. Программа выходит в главный цикл.

Можно управлять портами - включать/выключать светодиоды.

Таймер работает.

 

Программирую микроконтроллер через H-Jtag.

Программа хранится во внутренней flash памяти.

 

flash.lds, board_cstartup.S, board_lowlevel.c, board_memories.c взяты из примеров ATMEL. В board_lowlevel.c отменен Remap. board_memories.c скорректирован с учетом размера используемой памяти.

 

-------------------------------------------------------------------------------

обработка прерываний в board_cstartup.S

 

//------------------------------------------------------------------------------

/// Handles incoming interrupt requests by branching to the corresponding

/// handler, as defined in the AIC. Supports interrupt nesting.

//------------------------------------------------------------------------------

irqHandler:

 

/* Save interrupt context on the stack to allow nesting */

sub lr, lr, #4

stmfd sp!, {lr}

mrs lr, SPSR

stmfd sp!, {r0, lr}

 

/* Write in the IVR to support Protect Mode */

ldr lr, =AT91C_BASE_AIC

ldr r0, [lr, #AIC_IVR]

str lr, [lr, #AIC_IVR]

 

/* Branch to interrupt handler in Supervisor mode */

msr CPSR_c, #ARM_MODE_SVC

stmfd sp!, {r1-r3, r4, r12, lr}

blx r0

 

/* Restore scratch/used registers and LR from User Stack */

/* Disable Interrupt and switch back in IRQ mode */

ldmia sp!, {r1-r3, r4, r12, lr}

msr CPSR_c, #ARM_MODE_IRQ | I_BIT

 

/* Acknowledge interrupt */

ldr lr, =AT91C_BASE_AIC

str lr, [lr, #AIC_EOICR]

 

/* Restore interrupt context and branch back to calling code */

ldmia sp!, {r0, lr}

msr SPSR_cxsf, lr

ldmia sp!, {pc}^

-------------------------------------------------------------

Инициализация прерываний в board_lowlevel.c

 

/* Initialize AIC

****************/

AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF;

AT91C_BASE_AIC->AIC_SVR[0] = (unsigned int) defaultFiqHandler;

for (i = 1; i < 31; i++) {

 

AT91C_BASE_AIC->AIC_SVR = (unsigned int) defaultIrqHandler;

}

AT91C_BASE_AIC->AIC_SPU = (unsigned int) defaultSpuriousHandler;

 

// Unstack nested interrupts

for (i = 0; i < 8 ; i++) {

 

AT91C_BASE_AIC->AIC_EOICR = 0;

}

--------------------------------------------

Конфигурация таймера в main.c:

--------------------------------------------

 

//------------------------------------------------------------------------------

/// Configures Timer Counter 2 (TC2) to generate an interrupt every 1s.

//------------------------------------------------------------------------------

void ConfigureTc2(void)

{

unsigned int divv, tcclks;

 

// Enable TC2 peripheral clock

PMC_EnablePeripheral(AT91C_ID_TC2);

 

/// 1s (= 1Hz)

TC_FindMckDivisor(1, BOARD_MCK, &divv, &tcclks);

 

TC_Configure(AT91C_BASE_TC2, tcclks | AT91C_TC_CPCTRG);

AT91C_BASE_TC2->TC_RC = (BOARD_MCK / divv)/1; // timerFreq / desiredFreq

 

// Configure interrupt on RC compare

AIC_ConfigureIT(AT91C_ID_TC2, 0, ISR_Tc2);

AT91C_BASE_TC2->TC_IER = AT91C_TC_CPCS;

AIC_EnableIT(AT91C_ID_TC2);

}

 

 

Обработка прерывания

------------------------------

void ISR_Tc2(void)

{

TC_Stop(AT91C_BASE_TC2); // таймер стоп

 

// Clear status bit to acknowledge interrupt

AT91C_BASE_TC2->TC_SR;

 

PIO_Set(&LED_PWR); // светодиод "Питание ВЫКЛ."

 

TC_Start(AT91C_BASE_TC2); // таймер старт

}

 

Плата содержит внешнюю память SDRAM и NANDFLASH, но пока они не инициализируются, не используются.

 

Буду благодарен за любую помощь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...

 

Я использовал примерно такую инициализацию таймера на SAM9260.

 

void AT91F_TC_Open ( AT91PS_TC TC_pt, unsigned int Mode, unsigned int TimerId)
{
    //* First, enable the clock of the TIMER
        AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<< TimerId );

    //* Disable the clock and the interrupts
    TC_pt->TC_CCR = AT91C_TC_CLKDIS;
    TC_pt->TC_IDR = 0xFFFFFFFF;

    //* Clear status bit
        TC_pt->TC_SR;
    //* Set the Mode of the Timer Counter
    TC_pt->TC_CMR = Mode | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_WAVE;

        if( Mode == AT91C_TC_CLKS_TIMER_DIV1_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 2000;
        if( Mode == AT91C_TC_CLKS_TIMER_DIV2_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 8000;
        if( Mode == AT91C_TC_CLKS_TIMER_DIV3_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 32000;
        if( Mode == AT91C_TC_CLKS_TIMER_DIV4_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 128000;
    //* Set the value of the reg RC
        Var_Period_pwm_us_timer0 = (unsigned int)Period_pwm_us;
        Var_Frequency_pwm_kHz_timer0 = ((100000  / Var_Period_pwm_us_timer0)+5)/10;
    TC_pt->TC_RC = ((unsigned int)Period_pwm_us * T_clk_T0) / 1000;
    //* Enable the clock
    TC_pt->TC_CCR = AT91C_TC_CLKEN;
}

void timer_init ( void )
//* Begin
{

    //* Open timer0
    AT91F_TC_Open(AT91C_BASE_TC0,(unsigned int)CLKS_TIMER0,AT91C_ID_TC0);
        
    //* Start timer0
        AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
      
       
}





void init_timer2( unsigned int OverFlow, unsigned char Max_Dev  ) {
  double Value;
        AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<< AT91C_ID_TC2 );
    AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS;
    AT91C_BASE_TC2->TC_IDR = 0xFFFFFFFF;
        AT91C_BASE_TC2->TC_SR;
    AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_WAVE;
        Value = 0.5 + (AT91B_MASTER_CLOCK / 1000000.0) * (OverFlow / 128.0);
        Value = Value;
     
        AT91C_BASE_TC2->TC_RC  = 38924;                  
    AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN;  
        AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_TC2, TIMER2_INTERRUPT_LEVEL,
                                AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, timer2_c_irq_handler);
        AT91C_BASE_TC2->TC_IER = AT91C_TC_CPCS;  
    AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC2);
        AT91C_BASE_TC2->TC_CCR = AT91C_TC_SWTRG;  
    return;
}

Изменено пользователем skyv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я использовал примерно такую инициализацию таймера на SAM9260.

 

void AT91F_TC_Open ( AT91PS_TC TC_pt, unsigned int Mode, unsigned int TimerId)
{
    //* First, enable the clock of the TIMER
        AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<< TimerId );

    //* Disable the clock and the interrupts
    TC_pt->TC_CCR = AT91C_TC_CLKDIS;
    TC_pt->TC_IDR = 0xFFFFFFFF;

    //* Clear status bit
        TC_pt->TC_SR;
    //* Set the Mode of the Timer Counter
    TC_pt->TC_CMR = Mode | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_WAVE;

        if( Mode == AT91C_TC_CLKS_TIMER_DIV1_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 2000;
        if( Mode == AT91C_TC_CLKS_TIMER_DIV2_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 8000;
        if( Mode == AT91C_TC_CLKS_TIMER_DIV3_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 32000;
        if( Mode == AT91C_TC_CLKS_TIMER_DIV4_CLOCK ) T_clk_T0 = AT91B_MASTER_CLOCK / 128000;
    //* Set the value of the reg RC
        Var_Period_pwm_us_timer0 = (unsigned int)Period_pwm_us;
        Var_Frequency_pwm_kHz_timer0 = ((100000  / Var_Period_pwm_us_timer0)+5)/10;
    TC_pt->TC_RC = ((unsigned int)Period_pwm_us * T_clk_T0) / 1000;
    //* Enable the clock
    TC_pt->TC_CCR = AT91C_TC_CLKEN;
}

void timer_init ( void )
//* Begin
{

    //* Open timer0
    AT91F_TC_Open(AT91C_BASE_TC0,(unsigned int)CLKS_TIMER0,AT91C_ID_TC0);
        
    //* Start timer0
        AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
      
       
}





void init_timer2( unsigned int OverFlow, unsigned char Max_Dev  ) {
  double Value;
        AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<< AT91C_ID_TC2 );
    AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS;
    AT91C_BASE_TC2->TC_IDR = 0xFFFFFFFF;
        AT91C_BASE_TC2->TC_SR;
    AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_WAVE;
        Value = 0.5 + (AT91B_MASTER_CLOCK / 1000000.0) * (OverFlow / 128.0);
        Value = Value;
     
        AT91C_BASE_TC2->TC_RC  = 38924;                  
    AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN;  
        AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_TC2, TIMER2_INTERRUPT_LEVEL,
                                AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, timer2_c_irq_handler);
        AT91C_BASE_TC2->TC_IER = AT91C_TC_CPCS;  
    AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC2);
        AT91C_BASE_TC2->TC_CCR = AT91C_TC_SWTRG;  
    return;
}

 

 

Спасибо за ответ.

 

У меня инициализация делается такими же методами. Отличий нет.

Поэтому пока проблема не решена.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чудес не бывает, что-то упускаете.

Я бы выкинул все лишние и попытался настроить прерывание только от таймера для начала. Посмотрите, входит ли хоть раз в обработчик. Средства для этого у Вас имеются.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чудес не бывает, что-то упускаете.

Я бы выкинул все лишние и попытался настроить прерывание только от таймера для начала. Посмотрите, входит ли хоть раз в обработчик. Средства для этого у Вас имеются.

 

Спасибо за совет.

В обработчик не входит.

Выяснил, что прерывание по таймеру работает, просто по нему происходит перезапуск контроллера, а не запускается обработчик ,указанный в конфигурации таймера.

Есть подозрение - что то не так в файлах board_cstartup.S, board_lowlevel.c. В них задается первоначальная конфигурация всего контроллера, в том числе и конфигурация прерываний.

Но пока не могу понять что не так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

просто по нему происходит перезапуск контроллера, а не запускается обработчик ,указанный в конфигурации таймера.

При срабатывании прерывания от таймера Вы должны попасть на метку irqHandler в board_cstartup.S, а там уже вызовется обработчик таймера. Посмотрите, попадаете ли туда. Сброс контроллера говорит о том, что попадаете на мусор.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Проблема решена!

В board_lowlevel.c была закоментирована строка BOARD_RemapRam();, именно поэтому при срабатывании прерывания происходил перезапуск программы - т.е. программа переходила не на секцию .vectors, отвечающую за обработку векторов исключений, описанную в board_cstartup.S, а на область flash памяти, где записана программа.

Спасибо всем кто помог разобраться.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...