Цель - запустить на указанном контроллере TIMER0 и подрыгать из этого таймера ножкой. Никакой практической цели пока что не преследуется - просто освоение. За основу взял код из примеров и BSP, но писал по большей части с нуля, лишь подглядывая туда за общей идеей.
Итак, исходные данные:
Компилятор: IAR 5.40
main.c
Код
void main(void)
{
InitLPCPeripherials();
__enable_interrupt();
while(1);
}
{
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 - поправьте меня, если я не прав).