Записная книжка разработчика

Мои проекты

IAR, Cortex M3 и C++

| Comments

При перетаскивании проекта с LPC2368 (ядро ARM7TDMI) на LPC1768, который является pin-to-pin совместимым с LPC2368, но на ядре Cortex M3, столкнулся со следующими проблемами и особенностями:

В LPC1768 существенно изменена архитектура VIC (Vectored Interrupt Controller), т.е. контроллера прерываний.

В проекте LPC2368 были две функции, одна из которых предназначалась для инициализации VIC и сброса всех векторов прерываний в 0 (VIC_Init), а вторая для установки функции в качестве вектора прерывания с назначением ему нужного приоритета (VIC_SetVectoredIRQ):

/*************************************************************************
 * Function Name: VIC_Init
 * Parameters: void
 * Return: void
 *
 * Description: Initialize VIC
 *
 *************************************************************************/
void VIC_Init(void)
{
volatile unsigned long * pVecAdd, *pVecCntl;
int i;
  // Assign all interrupt channels to IRQ
  VICINTSELECT  =  0;
  // Disable all interrupts
  VICINTENCLEAR = 0xFFFFFFFF;
  // Clear all software interrupts
  VICSOFTINTCLEAR = 0xFFFFFFFF;
  // VIC registers can be accessed in User or privileged mode
  VICPROTECTION = 0;
  // Clear interrupt
  VICADDRESS = 0;
  // Clear address of the Interrupt Service routine (ISR) for vectored IRQs
  // and disable all vectored IRQ slots
  for(i = 0,  pVecCntl = &VICVECTPRIORITY0, pVecAdd = &VICVECTADDR0; i < 32; ++i)
  {
    *pVecCntl++ = *pVecAdd++ = 0;
  }
}
*************************************************************************
 * Function Name: VIC_SetVectoredIRQ
 * Parameters:  void(*pIRQSub)()
 *              unsigned int VicIrqSlot
 *              unsigned int VicIntSouce
 *
 * Return: void
 *
 * Description:  Init vectored interrupts
 *
 *************************************************************************/
void VIC_SetVectoredIRQ(void(*pIRQSub)(), unsigned int Priority,
                        unsigned int VicIntSource)
{
unsigned long volatile *pReg;
  // load base address of vectored address registers
  pReg = &VICVECTADDR0;
  // Set Address of callback function to corresponding Slot
  *(pReg+VicIntSource) = (unsigned long)pIRQSub;
  // load base address of ctrl registers
  pReg = &VICVECTPRIORITY0;
  // Set source channel and enable the slot
  *(pReg+VicIntSource) = Priority;
  // Clear FIQ select bit
  VICINTSELECT &= ~(1<<VicIntSource);
}

В примерах кода в IAR обработчиками прерываний заведует файл "cstartup_M.s", которого не было в проекте LPC2368. Он определяет имена дефолтных обработчиков, в таком стиле:

__vector_table_0x1c
        DCD     0                           ; Reserved
        DCD     0                           ; Reserved
        DCD     0                           ; Reserved
        DCD     0                           ; Reserved
        DCD     SVC_Handler                 ; SVCall Handler
        DCD     DebugMon_Handler            ; Debug Monitor Handler
        DCD     0                           ; Reserved
        DCD     PendSV_Handler              ; PendSV Handler
        DCD     SysTick_Handler             ; SysTick Handler
        DCD     WDT_IRQHandler              ; Watchdog Handler
        DCD     TMR0_IRQHandler             ; TIMER0 Handler
        DCD     TMR1_IRQHandler             ; TIMER1 Handler
        DCD     TMR2_IRQHandler             ; TIMER2 Handler
        DCD     TMR3_IRQHandler             ; TIMER3 Handler
        DCD     UART0_IRQHandler            ; UART0 Handler
        DCD     UART1_IRQHandler            ; UART1 Handler
        DCD     UART2_IRQHandler            ; UART2 Handler
        DCD     UART3_IRQHandler            ; UART3 Handler
        DCD     PWM1_IRQHandler             ; PWM1 Handler

Т.е. обработчик прерывания таймера 0 описывается в прогамме как функция TMR0_IRQHandler(void). Допустим, что функции-обработчики находятся в файле main.c.

Проблема в том, что, пока файл main имеет расширение ".с", всё работает, как только мы меняем расширение на ".срр", обработчики прерываний работать перестают.

Решение оказалось очень простым: перед обработчиками нужно поставить "extern "C"":

extern "C" void TMR0_IRQHandler (void)

и они начинают работать нормально.
Собственно, всё, что требуется от программиста, помимо описания функций-обработчиков, это назначение им необходимого приоритета такой функцией:

/*************************************************************************
* Function Name: NVIC_ClrPend
* Parameters: IntNumber - Interrup number, Interrupt Priority
* Return: void
*
* Description:Sets Interrupt priority
*
*
*************************************************************************/
void NVIC_IntPri(Int32U IntNumber, Int8U Priority)
{
volatile Int8U * pNVIC_IntPri = (Int8U *)&IP0;
assert((NVIC_WDT <= IntNumber) && (NVIC_PLL1 >= IntNumber));
IntNumber -= NVIC_WDT;
pNVIC_IntPri += IntNumber;
*pNVIC_IntPri = Priority;
}