реклама на сайте
подробности

 
 
> PIT в at91sam7s256, Работа по прерываниям
mempfis_
сообщение Mar 25 2010, 14:52
Сообщение #1


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Из работающего атмеловского примера выделил код настройки AIC и PIT для организации работы по прерываниям.
Собственно ниже то что получилось.

CODE


void IRQ_ConfigureIT(unsigned int source, unsigned int mode, void( *handler )( void ))
{
// Disable the interrupt first
AT91C_BASE_AIC->AIC_IDCR = 1 << source;

// Configure mode and handler
AT91C_BASE_AIC->AIC_SMR[source] = mode;
AT91C_BASE_AIC->AIC_SVR[source] = (unsigned int) handler;

// Clear interrupt
AT91C_BASE_AIC->AIC_ICCR = 1 << source;
}

//------------------------------------------------------------------------------
/// Enables interrupts coming from the given (unique) source (AT91C_ID_xxx).
/// \param source Interrupt source to enable.
//------------------------------------------------------------------------------
void IRQ_EnableIT(unsigned int source)
{
AT91C_BASE_AIC->AIC_IECR = 1 << source;
}

//------------------------------------------------------------------------------
/// Disables interrupts coming from the given (unique) source (AT91C_ID_xxx).
/// \param source Interrupt source to enable.
//------------------------------------------------------------------------------
void IRQ_DisableIT(unsigned int source)
{
AT91C_BASE_AIC->AIC_IDCR = 1 << source;
}


//------------------------------------------------------------------------------
void PIT_Init(unsigned int period, unsigned int pit_frequency)
{
AT91C_BASE_PITC->PITC_PIMR = period? (period * pit_frequency + 8) >> 4 : 0;
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
}

//------------------------------------------------------------------------------
/// Set the Periodic Interval Value of the PIT.
/// \param piv PIV value to set.
//------------------------------------------------------------------------------
void PIT_SetPIV(unsigned int piv)
{
AT91C_BASE_PITC->PITC_PIMR = (AT91C_BASE_PITC->PITC_PIMR & AT91C_PITC_PIV)
| piv;
}

//------------------------------------------------------------------------------
/// Enables the PIT if this is not already the case.
//------------------------------------------------------------------------------
void PIT_Enable(void)
{
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
}

//----------------------------------------------------------------------------
/// Enable the PIT periodic interrupt.
//----------------------------------------------------------------------------
void PIT_EnableIT(void)
{
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITIEN;
}

//------------------------------------------------------------------------------
/// Disables the PIT periodic interrupt.
//------------------------------------------------------------------------------
void PIT_DisableIT(void)
{
AT91C_BASE_PITC->PITC_PIMR &= ~AT91C_PITC_PITIEN;
}

//------------------------------------------------------------------------------
/// Returns the value of the PIT mode register.
/// \return PIT_MR value.
//------------------------------------------------------------------------------
unsigned int PIT_GetMode(void)
{
return AT91C_BASE_PITC->PITC_PIMR;
}

//------------------------------------------------------------------------------
/// Returns the value of the PIT status register, clearing it as a side effect.
/// \return PIT_SR value.
//------------------------------------------------------------------------------
unsigned int PIT_GetStatus(void)
{
return AT91C_BASE_PITC->PITC_PISR;
}

//------------------------------------------------------------------------------
/// Returns the value of the PIT Image Register, to read PICNT and CPIV without
/// clearing the current values.
/// \return PIT_PIIR value.
//------------------------------------------------------------------------------
unsigned int PIT_GetPIIR(void)
{
return AT91C_BASE_PITC->PITC_PIIR;
}

//------------------------------------------------------------------------------
/// Returns the value of the PIT Value Register, clearing it as a side effect.
/// \return PIT_PIVR value.
//------------------------------------------------------------------------------
unsigned int PIT_GetPIVR(void)
{
return AT91C_BASE_PITC->PITC_PIVR;
}

//------------------------------------------------------------------------------
/// Handler for PIT interrupt. Increments the timestamp counter.
//------------------------------------------------------------------------------

void ISR_Pit(void)
{
unsigned int status;

// Read the PIT status register
status = PIT_GetStatus() & AT91C_PITC_PITS;
if (status != 0) {
// 1 = The Periodic Interval timer has reached PIV since the last read of PIT_PIVR.
// Read the PIVR to acknowledge interrupt and get number of ticks
//Returns the number of occurrences of periodic intervals since the last read of PIT_PIVR.
timestamp += (PIT_GetPIVR() >> 20);
}
}

//------------------------------------------------------------------------------
/// Configure the periodic interval timer (PIT) to generate an interrupt every
/// millisecond.
//------------------------------------------------------------------------------
void ConfigurePit(void)
{
// Initialize the PIT to the desired frequency
PIT_Init(PIT_PERIOD, BOARD_MCK / 1000000);

// Configure interrupt on PIT
IRQ_DisableIT(AT91C_ID_SYS);
IRQ_ConfigureIT(AT91C_ID_SYS, AT91C_AIC_PRIOR_LOWEST, ISR_Pit);
IRQ_EnableIT(AT91C_ID_SYS);
PIT_EnableIT();

// Enable the pit
PIT_Enable();
}


void main(void)
{
//разрешение тактирования pio
AT91C_BASE_PMC->PMC_PCER = (1ul<<AT91C_ID_PIOA)|(1ul<<AT91C_ID_SYS)|(1ul<<AT91C_ID_FIQ);

//попытка настройки gpio
AT91C_BASE_PIOA->PIO_OER = (1ul<<3)|(1ul<<2)|(1ul<<1)|(1ul<<0);
AT91C_BASE_PIOA->PIO_SODR = (1ul<<3)|(1ul<<2)|(1ul<<1)|(1ul<<0);

//настройка PIT, 1mС, установлено прерывание
ConfigurePit();

long status=0;

for(;;)
{
static long timer=1000000;
if(timer > 0) timer--;
else
{
timer=1000000;

if(status == 0)
{
//устанавливаем ножку
AT91C_BASE_PIOA->PIO_SODR = (1ul<<3)|(1ul<<2)|(1ul<<1)|(1ul<<0);
status = 1;
}
else
{
//сбрасываем ножку
AT91C_BASE_PIOA->PIO_CODR = (1ul<<3)|(1ul<<2)|(1ul<<1)|(1ul<<0);
status = 0;
}
}
}



Код в основном цикле использую для того чтобы убедится что процессор работает. Точнее он работает если в ConfigurePIT() закоментировать разрешение прерывания PIT PIT_EnableIT(). Отличие моего проекта от атмеловского в том что я пытаюсь настроить только одно прерывание а там учавствуют несколько (от таймера, PIO).
Думал что проблема могла быть в том что не подключил тактирование AIC. На всякий случай ввёл
Код
AT91C_BASE_PMC->PMC_PCER = (1ul<<AT91C_ID_PIOA)|(1ul<<AT91C_ID_SYS)|(1ul<<AT91C_ID_FIQ);

Не помогло. Вероятно я чтото упускаю в коде или настройках.

P.S. Вопрос на засыпку - у меня тактовая частота процессора 48MHz (планируется использование USB). И при этом исполняю код только из flash. Не слишком ли это высокая частота?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
aaarrr
сообщение Mar 25 2010, 15:41
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(mempfis_ @ Mar 25 2010, 17:52) *
Собственно ниже то что получилось.

Получился ужас в худших атмеловских традициях - огромная куча мелких и совершенно бессмысленных процедур типа "поставить бит в регистре" sad.gif
С ошибками, кстати:
Код
//------------------------------------------------------------------------------
/// Set the Periodic Interval Value of the PIT.
/// \param piv  PIV value to set.
//------------------------------------------------------------------------------
void PIT_SetPIV(unsigned int piv)
{
    AT91C_BASE_PITC->PITC_PIMR = (AT91C_BASE_PITC->PITC_PIMR & AT91C_PITC_PIV)
                                 | piv;
}


Цитата(mempfis_ @ Mar 25 2010, 17:52) *
Думал что проблема могла быть в том что не подключил тактирование AIC. На всякий случай ввёл
Код
AT91C_BASE_PMC->PMC_PCER = (1ul<<AT91C_ID_PIOA)|(1ul<<AT91C_ID_SYS)|(1ul<<AT91C_ID_FIQ);

Не помогло. Вероятно я чтото упускаю в коде или настройках.

Тактирование SYS и FIQ включать бесполезно.
Очень похоже, что упускаете правильное оформление процедуры прерывания. Что живет на векторе IRQ?
Или, как вариант, где-то включен еще один источник SYS.

Цитата(mempfis_ @ Mar 25 2010, 17:52) *
P.S. Вопрос на засыпку - у меня тактовая частота процессора 48MHz (планируется использование USB). И при этом исполняю код только из flash. Не слишком ли это высокая частота?

Флеш должна работать с одним вейтстейтом на частотах выше 30MHz.
Go to the top of the page
 
+Quote Post
mempfis_
сообщение Mar 26 2010, 09:48
Сообщение #3


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Цитата(aaarrr @ Mar 25 2010, 18:41) *
Очень похоже, что упускаете правильное оформление процедуры прерывания. Что живет на векторе IRQ?
Или, как вариант, где-то включен еще один источник SYS.


Распишу по частям как у меня инициализируется прерывание

Сразу после настройки PLL инициализирую AIC дефолтными значениеями

CODE

void defaultSpuriousHandler( void )
{
while (1);
}

void defaultFiqHandler( void )
{
while (1);
}

void defaultIrqHandler( void )
{
while (1);
}

// Initialize AIC
AT91C_BASE_AIC->AIC_IDCR = 0xFFFFFFFF; //запрет всех прерываний
AT91C_BASE_AIC->AIC_SVR[0] = (unsigned int) defaultFiqHandler; //инициализация вектора FIQ
for (i = 1; i < 31; i++) {

AT91C_BASE_AIC->AIC_SVR[i] = (unsigned int) defaultIrqHandler; //инициализация вектора IRQ
}
AT91C_BASE_AIC->AIC_SPU = (unsigned int) defaultSpuriousHandler;

// Unstack nested interrupts
for (i = 0; i < 8 ; i++) {

AT91C_BASE_AIC->AIC_EOICR = 0;
}


Далее настройка прерывания PIT

CODE

void ConfigurePit(void)
{
/настройка PIT на 1мС
PIT_Init(PIT_PERIOD, BOARD_MCK / 1000000); /

//Настройка прерывния PIT
AT91C_BASE_AIC->AIC_IDCR = 1 << AT91C_ID_SYS; //запрет прерывания от SYS (PIT)

// Configure mode and handler
AT91C_BASE_AIC->AIC_SMR[source] = AT91C_AIC_PRIOR_LOWEST; //наинизший приоритет (0)
AT91C_BASE_AIC->AIC_SVR[source] = (unsigned int) ISR_Pit; //вектор прерывания - ISR_Pit()

// Очистка прерывания
AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_SYS;

//разрешаем прерывание от SYS (PIT)
AT91C_BASE_AIC->AIC_IECR = 1 << AT91C_ID_SYS;

//разрешение прерывания PIT
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITIEN;

//разрешаем PIT
AT91C_BASE_PITC->PITC_PIMR |= AT91C_PITC_PITEN;
}


Собственно сам обработчика прерывания

Код
void ISR_Pit(void)
{
    unsigned int status;

    // Read the PIT status register
    status = AT91C_BASE_PITC->PITC_PISR & AT91C_PITC_PITS;
    if (status != 0) {
        // 1 = The Periodic Interval timer has reached PIV since the last read of PIT_PIVR.
        // Read the PIVR to acknowledge interrupt and get number of ticks
        //Returns the number of occurrences of periodic intervals since the last read of PIT_PIVR.
        timestamp += (PIT_GetPIVR() >> 20);
    }
}


кроме того в стартапе есть такой код

Код
/*
   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, [r14, #AIC_IVR]
        STR     lr, [r14, #AIC_IVR]

        /* Branch to interrupt handler in Supervisor mode */
        MSR     CPSR_c, #ARM_MODE_SYS
        STMFD   sp!, {r1-r3, r4, r12, lr}
        MOV     lr, pc
        BX      r0
        LDMIA   sp!, {r1-r3, r4, r12, lr}
        MSR     CPSR_c, #ARM_MODE_IRQ | I_BIT

        /* Acknowledge interrupt */
        LDR     lr, =AT91C_BASE_AIC
        STR     lr, [r14, #AIC_EOICR]

        /* Restore interrupt context and branch back to calling code */
        LDMIA   sp!, {r0, lr}
        MSR     SPSR_cxsf, lr
        LDMIA   sp!, {pc}^


Я запутался в логике работы AIC. При возникновении прерывания IRQ процессор начинает исполнять код irqHandler. Вектор прерывания берётся из AIC_IVR. Идёт исполнение по этому вектору (в моём случае должна выполниться функция ISR_Pit()). После исполнения идёт возврат в irqHandler. Далее процедура выхода из прерывания. Как я предполагаю собственно всё.... Далее ждём следующего прерывания.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 23:57
Рейтинг@Mail.ru


Страница сгенерированна за 0.01407 секунд с 7
ELECTRONIX ©2004-2016