Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LPC2478 прерывание TIMER0
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
alvy
Поскольку с LPC до этого не работал (есть только опыт работы с SAM7X), то тему создал именно в разделе для начинающих...

Цель - запустить на указанном контроллере TIMER0 и подрыгать из этого таймера ножкой. Никакой практической цели пока что не преследуется - просто освоение. За основу взял код из примеров и BSP, но писал по большей части с нуля, лишь подглядывая туда за общей идеей.

Итак, исходные данные:
Компилятор: IAR 5.40

main.c
Код
void main(void)
{

    InitLPCPeripherials();
    __enable_interrupt();
    while(1);
}


system.c (оставлены основные функции)
CODE

void InitLPCPeripherials (void)
{

    InitPLL();
    InitGPIO();
    InitVIC();
    InitTickTimer();
}


static void InitPLL (void)
{
    // 1. Настройка System Controls and Status register (SCS).
    // OSCRANGE=0 - частотный диапазон главного генератора от 1МГц до 20МГц
    // OSCEN=1 - главный генератор включен и запустится, если к XTAL1 и XTAL2
    // подцеплены правильные сигналы
    SCS_bit.OSCRANGE = 0;
    SCS_bit.OSCEN = 1;

    // 2.  Ждем сигнала о готовности OSC
    while(!SCS_bit.OSCSTAT);
    // 3. Отключаем соединение PLL (PLLCON - PLL Control Register)
    // PLLC - PLL Connect
    // PLL - Feed register. Для того, чтобы изменения в регистрах PLLCON и PLLCFG
    // вступили в силу, в регистр PLLFEED должна быть последовательно записана
    // следующая комбинация: 0xAA, 0x55
    PLLCON_bit.PLLC = 0;

    PLLFEED = 0xAA;
    PLLFEED = 0x55;
    // 4. Отключаем PLL (PLLE - PLL Enable)

    PLLCON_bit.PLLE = 0;
    PLLFEED = 0xAA;
    PLLFEED = 0x55;
    // 5. Выбираем источник сигнала для PLL
    CLKSRCSEL_bit.CLKSRC = 1; // Источник для PLL - главный генератор

    // 6. Устанавливаем частоту PLL (Fcco) в 288МГц
    // MSEL - PLL Multiplier value, NSEL - PLL Pre-Divider value
    // Выходная частота PLL может быть получена из выражения:
    // Fcco = (2 x M x Fin) / N, где Fin в пределах от 32 kHz до 50 MHz,
    // Fcco в пределах от 275 MHz до 550 MHz
    // В нашем случае   Fin = 12МГц
    PLLCFG_bit.MSEL = (12 - 1);
   PLLCFG_bit.NSEL = (2 - 1);
   PLLFEED = 0xAA;
    PLLFEED = 0x55;

    // 7. Включаем PLL
    PLLCON_bit.PLLE = 1;
    PLLFEED = 0xAA;
    PLLFEED = 0x55;

    // 8. Дожидаемся готовности PLL
    while(!PLLSTAT_bit.PLOCK);

    // 9. Установки делителей PLL для периферии
    // CCLKCFG - CPU Clock Configuration register, частота CPU
    CCLKCFG   = 4-1;            // 1/4 Fpll - 72 MHz
    // USBCLKCFG - USB Clock Configuration register, частота USB
    USBCLKCFG = 6-1;            // 1/6 Fpll - 48 MHz
    // Peripheral Clock Selection registers
    PCLKSEL0 = PCLKSEL1 = 0;    // остальная периферия - 18MHz (Fcclk/4)

    // 10. Соединяем PLL в схему генерации
    PLLCON_bit.PLLC = 1;
    PLLFEED = 0xAA;
    PLLFEED = 0x55;

    // Останавливаем все периферийные генераторы
    PCONP = 0;

    // Configure AHB1 arbitration
    AHBCFG1_bit.SHDL = 0;     // priority arbitration

    AHBCFG1_bit.BB   = 0;     // Never break defined length bursts.
    AHBCFG1_bit.QT   = 0;     // A quantum is an AHB clock.
    AHBCFG1_bit.QT   = 4;     // Preemptive, re-arbitrate after 16 AHB quanta.
    AHBCFG1_bit.DM   = 1;     // Master 1 (CPU) is the default master.
    AHBCFG1_bit.EP1  = 1;     // External priority for master 1 (CPU).
    AHBCFG1_bit.EP2  = 2;     // External priority for master 2 (GPDMA).
    AHBCFG1_bit.EP3  = 3;     // External priority for master 3 (AHB1).
    AHBCFG1_bit.EP4  = 5;     // External priority for master 4 (USB).
    AHBCFG1_bit.EP5  = 4;     // External priority for master 5 (LCD).
}


INT32U GetCPUClkFreq (void)
{
INT32U msel;
INT32U nsel;
INT32U fin;
INT32U pll_clk_feq; /* When the PLL is enabled, this is Fcco. */
INT32U clk_div;
INT32U clk_freq;

//Determine the current clock source.
switch (CLKSRCSEL & 0x03)
{
default:
case 0:
fin = IRC_OSC_FRQ;
break;

case 1:
fin = MAIN_OSC_FRQ;
break;

case 2:
fin = RTC_OSC_FRQ;
break;
}

if ((PLLSTAT & (1 << 25)) > 0)
{ /* If the PLL is currently enabled and connected. */
msel = (INT32U)(PLLSTAT & 0x3FFF) + 1; /* Obtain the PLL multiplier. */
nsel = (INT32U)((PLLSTAT >> 16) & 0x0F) + 1; /* Obtain the PLL divider. */
pll_clk_feq = (2 * msel * (fin / nsel)); /* Compute the PLL output frequency. */
}
else
{
pll_clk_feq = (fin); /* The PLL is bypassed. */
}

clk_div = (INT32U)(CCLKCFG & 0xFF) + 1; /* Obtain the CPU core clock divider. */
clk_freq = (INT32U)(pll_clk_feq / clk_div); /* Compute the ARM Core clock frequency. */

return (clk_freq);
}


INT32U GetPclkFreq (INT8U pclk)
{
INT32U clk_freq;
INT32U pclk_freq;
INT32U selection;

clk_freq = GetCPUClkFreq();

switch (pclk)
{
case BSP_PCLK_WDT:
case BSP_PCLK_TIMER0:
case BSP_PCLK_TIMER1:
case BSP_PCLK_UART0:
selection = ((PCLKSEL0 >> 6) & 0x03);
if (selection == 0) {
pclk_freq = clk_freq / 4;
} else if (selection == 1) {
pclk_freq = clk_freq;
} else if (selection == 2) {
pclk_freq = clk_freq / 2;
} else {
pclk_freq = clk_freq / 8;
}
break;
case BSP_PCLK_UART1:
case BSP_PCLK_PWM0:
case BSP_PCLK_PWM1:
case BSP_PCLK_I2C0:
case BSP_PCLK_SPI:
case BSP_PCLK_RTC:
case BSP_PCLK_SSP1:
case BSP_PCLK_DAC:
case BSP_PCLK_ADC:
case BSP_PCLK_CAN1:
case BSP_PCLK_CAN2:
case BSP_PCLK_ACF:
selection = ((PCLKSEL0 >> (pclk * 2)) & 0x03);
if (selection == 0) {
pclk_freq = clk_freq / 4;
} else if (selection == 1) {
pclk_freq = clk_freq;
} else if (selection == 2) {
pclk_freq = clk_freq / 2;
} else {
pclk_freq = clk_freq / 8;
}
break;

case BSP_PCLK_BAT_RAM:
case BSP_PCLK_GPIO:
case BSP_PCLK_PCB:
case BSP_PCLK_I2C1:
case BSP_PCLK_SSP0:
case BSP_PCLK_TIMER2:
case BSP_PCLK_TIMER3:
case BSP_PCLK_UART2:
case BSP_PCLK_UART3:
case BSP_PCLK_I2C2:
case BSP_PCLK_MCI:
selection = ((PCLKSEL1 >> 24) & 0x03);
if (selection == 0) {
pclk_freq = clk_freq / 4;
} else if (selection == 1) {
pclk_freq = clk_freq;
} else if (selection == 2) {
pclk_freq = clk_freq / 2;
} else {
pclk_freq = clk_freq / 8;
}
break;

case BSP_PCLK_SYSCON:
selection = ((PCLKSEL1 >> ((pclk - 16) * 2)) & 0x03);
if (selection == 0) {
pclk_freq = clk_freq / 4;
} else if (selection == 1) {
pclk_freq = clk_freq;
} else if (selection == 2) {
pclk_freq = clk_freq / 2;
} else {
pclk_freq = clk_freq / 8;
}
break;

default:
pclk_freq = 0;
break;
}

return (pclk_freq);
}

static void InitGPIO (void)
{
INT32U pinsel;

IO0DIR = 0;
IO1DIR = 0;
FIO0DIR = 0;
FIO1DIR = 0;
FIO2DIR = 0;
FIO3DIR = 0;
FIO4DIR = 0;

FIO0MASK = 0;
FIO1MASK = 0;
FIO2MASK = 0;
FIO3MASK = 0;
FIO4MASK = 0;

FIO2DIR |= (1<<0);//Настраиваю P2.0 на выход
PINSEL4 = ~((1<<0)|(1<<1));//Настраиваю P2.0 на GPIO

FIO4DIR |= 0xFFFFFFFF;
PINSEL8 = ~0xFFFFFFFF;
}

static void InitTickTimer (void)
{
INT32U pclk_freq;
INT32U rld_cnts;

// Инициализация векторного прерывания для TIMER0
VICINTSELECT &= ~(1 << VIC_TIMER0); // конфигурируем прерывание от TIMER0 как IRQ
VICVECTADDR4 = (INT32U)Tmr_TickISR_Handler; // Указываем обработчик прерывания
VICVECTPRIORITY4 = 15; // Указываем приоритет прерывания

// Получаем частоту тактирования для периферии
pclk_freq = GetPclkFreq(BSP_PCLK_TIMER0);
// Вычисляем число тактов необходимое для заданного количества тиков ОС
rld_cnts = pclk_freq / OS_TICKS_PER_SEC;
// Сбрасываем счетчик и предделитель таймера (Counter Reset = 1)
T0TCR_bit.CR = 1;
// Сбрасываем бит Counter Reset
T0TCR = 0;
// Настраиваем предделитель - без делителя
T0PC = 0;

T0MR0 = rld_cnts;
// Прерывание по достижению значения в T0MR0, сброс TC по этому событию
T0MCR = 3; // MR0I = 1, MR0R = 1

T0CCR = 0; // захват отключен
T0EMR = 0; // внешние пины не контролируются

// Подаем питание для TIMER0
PCONP_bit.PCTIM0 = 1;

VICINTENABLE = (1 << VIC_TIMER0); //разрешаем прерывания для TIMER0
T0TCR = 1; // включаем таймер 0
}

void Tmr_TickISR_Handler (void)
{
if(trigger)
{
trigger = 0;
FIO2SET_bit.P2_0 = 1;
}
else
{
trigger = 1;
FIO2CLR_bit.P2_0 = 1;
}

//OSTimeTick(); /* Call uC/OS-II's OSTimeTick(). */

// Сбрасываем прерывание
T0IR_bit.MR0INT = 1;
VICADDRESS = 0;
}

static void InitVIC (void)
{
VICINTENCLEAR = 0xFFFFFFFF; // Запрещаем все прерывания
VICADDRESS = 0; // Acknowlege any pending VIC interrupt.
VICPROTECTION = 0; // Allow VIC reg access in User or Priviledged modes.

VICVECTADDR0 = (INT32U)BSP_VIC_DummyWDT; // Set the vector address.
VICVECTADDR1 = (INT32U)BSP_VIC_DummySW;
VICVECTADDR2 = (INT32U)BSP_VIC_DummyDEBUGRX;
VICVECTADDR3 = (INT32U)BSP_VIC_DummyDEBUGTX;
VICVECTADDR4 = (INT32U)BSP_VIC_DummyTIMER0;
VICVECTADDR5 = (INT32U)BSP_VIC_DummyTIMER1;
VICVECTADDR6 = (INT32U)BSP_VIC_DummyUART0;
VICVECTADDR7 = (INT32U)BSP_VIC_DummyUART1;
VICVECTADDR8 = (INT32U)BSP_VIC_DummyPWM01;
VICVECTADDR9 = (INT32U)BSP_VIC_DummyI2C0;
VICVECTADDR10 = (INT32U)BSP_VIC_DummySPI;
VICVECTADDR11 = (INT32U)BSP_VIC_DummySSP1;
VICVECTADDR12 = (INT32U)BSP_VIC_DummyPLL;
VICVECTADDR13 = (INT32U)BSP_VIC_DummyRTC;
VICVECTADDR14 = (INT32U)BSP_VIC_DummyEINT0;
VICVECTADDR15 = (INT32U)BSP_VIC_DummyEINT1;
VICVECTADDR16 = (INT32U)BSP_VIC_DummyEINT2;
VICVECTADDR17 = (INT32U)BSP_VIC_DummyEINT3;
VICVECTADDR18 = (INT32U)BSP_VIC_DummyAD0;
VICVECTADDR19 = (INT32U)BSP_VIC_DummyI2C1;
VICVECTADDR20 = (INT32U)BSP_VIC_DummyBOD;
VICVECTADDR21 = (INT32U)BSP_VIC_DummyETHERNET;
VICVECTADDR22 = (INT32U)BSP_VIC_DummyUSB;
VICVECTADDR23 = (INT32U)BSP_VIC_DummyCAN01;
VICVECTADDR24 = (INT32U)BSP_VIC_DummyMMC;
VICVECTADDR25 = (INT32U)BSP_VIC_DummyGP_DMA;
VICVECTADDR26 = (INT32U)BSP_VIC_DummyTIMER2;
VICVECTADDR27 = (INT32U)BSP_VIC_DummyTIMER3;
VICVECTADDR28 = (INT32U)BSP_VIC_DummyUART2;
VICVECTADDR29 = (INT32U)BSP_VIC_DummyUART3;
VICVECTADDR30 = (INT32U)BSP_VIC_DummyI2C2;
VICVECTADDR31 = (INT32U)BSP_VIC_DummyI2S;
}


cstartup.s
CODE

;
;*******************************************************************************
*************************
; EXCEPTION VECTORS & STARTUP CODE
;
; File : cstartup.s
; For : ARM7 or ARM9
; Toolchain : IAR EWARM V5.10 and higher
;*******************************************************************************
*************************
;

;*******************************************************************************
*************************
; MACROS AND DEFINIITIONS
;*******************************************************************************
*************************

; Mode, correspords to bits 0-5 in CPSR
MODE_BITS DEFINE 0x1F ; Bit mask for mode bits in CPSR
USR_MODE DEFINE 0x10 ; User mode
FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode
IRQ_MODE DEFINE 0x12 ; Interrupt Request mode
SVC_MODE DEFINE 0x13 ; Supervisor mode
ABT_MODE DEFINE 0x17 ; Abort mode
UND_MODE DEFINE 0x1B ; Undefined Instruction mode
SYS_MODE DEFINE 0x1F ; System mode


;*******************************************************************************
*************************
; ARM EXCEPTION VECTORS
;*******************************************************************************
*************************

SECTION .intvec:CODE:NOROOT(2)
PUBLIC __vector
PUBLIC __iar_program_start
PUBLIC __vector_0x14

IMPORT OS_CPU_ARM_ExceptUndefInstrHndlr
IMPORT OS_CPU_ARM_ExceptSwiHndlr
IMPORT OS_CPU_ARM_ExceptPrefetchAbortHndlr
IMPORT OS_CPU_ARM_ExceptDataAbortHndlr
IMPORT OS_CPU_ARM_ExceptIrqHndlr
IMPORT OS_CPU_ARM_ExceptFiqHndlr

ARM

__vector:
LDR PC, [PC,#24] ; Absolute jump can reach 4 GByte
LDR PC, [PC,#24] ; Branch to undef_handler
LDR PC, [PC,#24] ; Branch to swi_handler
LDR PC, [PC,#24] ; Branch to prefetch_handler
LDR PC, [PC,#24] ; Branch to data_handler
__vector_0x14:
DC32 0 ; Reserved
LDR PC, [PC,#24] ; Branch to irq_handler
LDR PC, [PC,#24] ; Branch to fiq_handler


DC32 __iar_program_start
DC32 OS_CPU_ARM_ExceptUndefInstrHndlr
DC32 OS_CPU_ARM_ExceptSwiHndlr
DC32 OS_CPU_ARM_ExceptPrefetchAbortHndlr
DC32 OS_CPU_ARM_ExceptDataAbortHndlr
DC32 0
DC32 OS_CPU_ARM_ExceptIrqHndlr
DC32 OS_CPU_ARM_ExceptFiqHndlr


;*******************************************************************************
*************************
; LOW-LEVEL INITIALIZATION
;*******************************************************************************
*************************

SECTION FIQ_STACK:DATA:NOROOT(3)
SECTION IRQ_STACK:DATA:NOROOT(3)
SECTION SVC_STACK:DATA:NOROOT(3)
SECTION ABT_STACK:DATA:NOROOT(3)
SECTION UND_STACK:DATA:NOROOT(3)
SECTION CSTACK:DATA:NOROOT(3)
SECTION text:CODE:NOROOT(2)
REQUIRE __vector
EXTERN ?main
PUBLIC __iar_program_start
EXTERN lowlevel_init

__iar_program_start:

;*******************************************************************************
*************************
; STACK POINTER INITIALIZATION
;*******************************************************************************
*************************

MRS r0,cpsr ; Original PSR value
BIC r0,r0,#MODE_BITS ; Clear the mode bits
ORR r0,r0,#SVC_MODE ; Set SVC mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(SVC_STACK) ; End of SVC_STACK

BIC r0,r0,#MODE_BITS ; Clear the mode bits
ORR r0,r0,#UND_MODE ; Set UND mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(UND_STACK) ; End of UND_STACK

BIC r0,r0,#MODE_BITS ; Clear the mode bits
ORR r0,r0,#ABT_MODE ; Set ABT mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(ABT_STACK) ; End of ABT_STACK

BIC r0,r0,#MODE_BITS ; Clear the mode bits
ORR r0,r0,#FIQ_MODE ; Set FIQ mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(FIQ_STACK) ; End of FIQ_STACK

BIC r0,r0,#MODE_BITS ; Clear the mode bits
ORR r0,r0,#IRQ_MODE ; Set IRQ mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(IRQ_STACK) ; End of IRQ_STACK

BIC r0,r0,#MODE_BITS ; Clear the mode bits
ORR r0,r0,#SYS_MODE ; Set System mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(CSTACK) ; End of CSTACK


;*******************************************************************************
*************************
; ADDITIONAL INITIALIZATION
;*******************************************************************************
*************************


;*******************************************************************************
*************************
; CONTINUE TO ?main FOR ADDITIONAL INITIALIZATION
;*******************************************************************************
*************************

LDR r0,=?main
BX r0

END


В результате, на выбранной ножке ничего не происходит. Если перекинуть "ногодрыганье" в цикл main, то на осциллографе виден период ногодрыганья в 200 кГц (что как мне кажется не соответствует частоте, на которую настроен PLL - поправьте меня, если я не прав).
zltigo
Цитата(alvy @ Mar 20 2010, 13:28) *
За основу взял код из примеров и BSP...

Вы бы для начала, вместо демонстрации возможностей copy-paste написали десяток строчек, но действительно своих. И начиная с малого постепенно разбирались-бы. А то слишком много букв sad.gif и разные неведомые OS_CPU_ARM_ExceptIrqHndlr - ошметки от операционной системы неведомо что и как делающие, но в результате предполагается, что почему-то должны попасть на желаемый обработчик... Периферия, кстати, настраивается ПОСЛЕ того, как на нее подали питание, а не до.
MiklPolikov
Помогите мне разобратmся с прерыванием от TIMER0 в LPC2148. Почему программа не попадает в TIMER0_IRQ, что я забыл ?

//////////////////////прерывание от таймера/////////////////////////////
void TIMER0_IRQ(void)
{
T0IR = 0x000000ff; //сбрасываем все флаги прерывания таймера.
VICVectAddr = 0x00; //сообщаем контроллеру прерываний о том что прерывание обработано
}

////////////////////////инициализация TIMER0/////////////////////////////
void init_TIMER0(void)
{
T0MCR|=(1<<0);// разрешаем прерывание по совпадению с регистром MR0
T0MCR|=(1<<1);// обнуляем счётный регистр после совпадения с MR0
T0MR0|=1000; //регистр сравнения MR0

T0IR = 0x000000ff; //сбрасываем все флаги прерывания таймера.

T0PR|=100; //Делитель частоты
T0TCR|=(1<<0);//запускаем счёт

VICVectAddr4=(unsigned long int)TIMER0_IRQ; //адрес вектора прерывания процедура TIMER0_IRQ
VICVectCntl4|=(4<<0); // Номер прерывания от TIMER0 4
VICVectCntl4|=(1<<5); //Включаем регистр, в который только что записали номер прерывания
VICIntEnable|=(1<<4); //Включаем прерывание от TIMER0
}


int main(void)
{
init_TIMER0();

while(1)
{
}

}
MiklPolikov
Отвечаю сам на свой вопрос :
Не хватало директивы __irq перед void TIMER0_IRQ(void)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.