VxWorks and LPC2106


Description



   The Wind River's VxWorks Real Time operating system generally is used in the mid-to-high size embedded systems with the considerable hardware resources (a few megabytes of the RAM, networking, etc).
   The VxWorks port for the LPC2106 ARM microprocessor shows an ability to use the VxWorks in the minimal configuration (a LPC2106 has 128 KBytes internal FLASH and 64 KBytes internal RAM).
   A Tornado 2.2/VxWorks 5.5 for ARM has been used for the BSP (board support package) development and a test project.

1. Minimal configuration

  In the file config.h (part of the LPC2106 BSP), all VxWorks's components, enabled in the system's file configAll.h, should be disabled. A Tornado's BSP/project creator automatically includes in the project minimal set of the components for the system (kernel) functionality (see the file prjComps.h in the test project directory):

/* minimal set of components - includes automatically*/

 #define INCLUDE_DLL  #define INCLUDE_EXC_HANDLING  #define INCLUDE_EXC_TASK  #define INCLUDE_KERNEL  #define INCLUDE_MEMORY_CONFIG  #define INCLUDE_MEM_MGR_BASIC  #define INCLUDE_MSG_Q  #define INCLUDE_SEM_BINARY  #define INCLUDE_SYSCLK_INIT  #define INCLUDE_SYSHW_INIT  #define INCLUDE_SYS_START  #define INCLUDE_USER_APPL  #define INCLUDE_VXEVENTS

2. Memory map

  A projects with the LPC2106 BSP use only the default_romResident build configuration (the system code are in the FLASH, a data segment is copied into the RAM)
  A BSP's memory configuration is described in the files Makefile and config.h (both are in the LPC2106 BSP's directory):

       - in the Makefile:

ROM_TEXT_ADRS       = 00000000 # ROM entry address
ROM_WARM_ADRS       = 00000048 # ROM warm entry address
ROM_SIZE            = 00020000 # number of bytes of ROM space

RAM_LOW_ADRS        = 40000600 # RAM text/data address ()
RAM_HIGH_ADRS       = 40000F00 # RAM text/data address (is not used)
   

     - in the config.h :

/*-------------- lpc2106base BSP configuration -----------------------*/
     
#undef ROOT_STACK_SIZE /* was 0x4000 */ #define ROOT_STACK_SIZE 0x800

#undef LOCAL_MEM_AUTOSIZE /* run-time memory sizing */ #define LOCAL_MEM_SIZE 0x10000 /* 64k */ #define USER_RESERVED_MEM 0x4000 /* 16k */ #define ROM_BASE_ADRS 0x00000000
#define ROM_TEXT_ADRS 0x00000000 /* code start addr in ROM */ #define ROM_SIZE 0x00020000 /* 128K */ #define ROM_COPY_SIZE ROM_SIZE
#define ROM_SIZE_TOTAL 0x00020000 /* total size of ROM */ #define RAM_LOW_ADRS 0x40000600 /* VxWorks image entry point */ #define RAM_HIGH_ADRS 0x40000F00 /* RAM address for ROM boot - is not used */ #define LOCAL_MEM_LOCAL_ADRS 0x40000000 /* LPC21XX RAM start addr*/ #define LOCAL_MEM_BUS_ADRS 0x00000000

#undef INT_MODE #define INT_MODE INT_NON_PREEMPT_MODEL

#undef ISR_STACK_SIZE #define ISR_STACK_SIZE 0x400 /* size of ISR stack, in bytes */ #define BUS BUS_TYPE_NONE
#define NV_RAM_SIZE NONE

3. Interrupts vectors

   After the hardware reset, the LPC2106 starts from the address 0x0 (a FLASH first address). Other exceptions vectors are placed at the addresses 0x04 - 0x1C.
  For the ARM architecture, a VxWorks expects that an exception pointers are placed (finally) at addreses 0x100-0x1C0 in the RAM.
   To set an exceptions vectors in the RAM, the romInit() function (an entry point for the VxWorks in the ROM/FLASH; a file romInit.s in the BSP directory) contains an exceptions redirection code:


_romInit:

      ldr  pc, L$_reset_handler_address
      ldr  pc, L$_undef_handler_address
      ldr  pc, L$_swi_handler_address
      ldr  pc, L$_pabort_handler_address
      ldr  pc, L$_dabort_handler_address
      .long   0xB8A06F58     /* LPC2XXX specific,
                                       0 - (sum of other vectors instructions) */
      ldr  pc, L$_irq_handler_address
      ldr  pc, L$_fiq_handler_address

L$_reset_handler_address:  .long  reset_handler
L$_undef_handler_address:  .long  LOCAL_MEM_LOCAL_ADRS + 0x04  /*undef_handler*/
L$_swi_handler_address:    .long  LOCAL_MEM_LOCAL_ADRS + 0x08  /*swi_handler*/
L$_pabort_handler_address: .long  LOCAL_MEM_LOCAL_ADRS + 0x0C  /*pabort_handler*/
L$_dabort_handler_address: .long  LOCAL_MEM_LOCAL_ADRS + 0x10  /*dabort_handler*/
                           .long  0x00
L$_irq_handler_address: .long LOCAL_MEM_LOCAL_ADRS + 0x18 /*irq_isr_handler*/ L$_fiq_handler_address: .long reset_handler /* FIQ is not processed*/ reset_handler: b cold cold: MOV r0, #BOOT_COLD /* fall through to warm boot entry */ warm: B start ...

  In the file sysLib.c (the BSP's directory), the lpc2106IntVectSet() function is added to make a final exception vectors remapping. This function's call should be placed inside the sysHwInit() function (to initialize the CPU board hardware).


/* This is a VxWorks's internal interrupt handling routines prototypes */

extern void excEnterUndef(void);
extern void excEnterSwi(void);
extern void excEnterPrefetchAbort(void);
extern void excEnterDataAbort(void);
extern void intEnt(void);

      ...

void lpc2106IntVectSet(void)
{
   unsigned int * ptr;

#define RAM_VECTORS_BASE  (LOCAL_MEM_LOCAL_ADRS + 0x100)

   /*--- Set instruction to call handlers ---*/
   ptr = (unsigned int *)(LOCAL_MEM_LOCAL_ADRS + 0x04);  /*undef_handler   */
   *ptr = 0xE59FF0F8;               /* ldr pc[pc,0xF8] ->  pc = pc + 0x100 */
   ptr = (unsigned int *)(LOCAL_MEM_LOCAL_ADRS + 0x08);  /*swi_handler     */
   *ptr = 0xE59FF0F8;               /* ldr pc[pc,0xF8] ->  pc = pc + 0x100 */
   ptr = (unsigned int *)(LOCAL_MEM_LOCAL_ADRS + 0x0C);  /*pabort_handler  */
   *ptr = 0xE59FF0F8;               /* ldr pc[pc,0xF8] ->  pc = pc + 0x100 */
   ptr = (unsigned int *)(LOCAL_MEM_LOCAL_ADRS + 0x10);  /*dabort_handler  */
   *ptr = 0xE59FF0F8;               /* ldr pc[pc,0xF8] ->  pc = pc + 0x100 */
   ptr = (unsigned int *)(LOCAL_MEM_LOCAL_ADRS + 0x18);  /*irq_isr_handler */
   *ptr = 0xE59FF0F8;               /* ldr pc[pc,0xF8] ->  pc = pc + 0x100 */

  /*--- Set handlers ---*/

   ptr = (unsigned int *)(RAM_VECTORS_BASE + 0x04);
   *ptr = (unsigned int)&excEnterUndef;

   ptr = (unsigned int *)(RAM_VECTORS_BASE + 0x08); /* you can use ptr++ instead */
   *ptr = (unsigned int)&excEnterSwi;

   ptr = (unsigned int *)(RAM_VECTORS_BASE + 0x0C);
   *ptr = (unsigned int)&excEnterPrefetchAbort;

   ptr = (unsigned int *)(RAM_VECTORS_BASE + 0x10);
   *ptr = (unsigned int)&excEnterDataAbort;

   ptr = (unsigned int *)(RAM_VECTORS_BASE + 0x18);
   *ptr = (unsigned int)&intEnt;
}

   VxWorks has the own internal function to initialize exception vectors - excVecInit(). This function has been written on the assumption that a RAM (not a ROM) is placed at the address 0x0. The usage this function in the LPC2106 BSP will crash a system.
   A problem here (to avoid this function's using) is that the Tornado's BSP/project creator automatically includes this function into the usrInit() function (a file prjConfig.c; the project directory) after each rebuilding of the project.
   A simple (and, probably, not the best) way to cancel this automatic including is to set as a comment name of the excVecInit()function in the file /target/config/comps/vxWorks/00vxWorks.cdf:

    Component INCLUDE_EXC_HANDLING {
            NAME                exception handling
            MODULES             excArchLib.o
            INIT_RTN            /* excVecInit (); */
            HDR_FILES           excLib.h
    }
   

4. Interrupts controller


   An interrupts controller's routines for the LPC2106 are very similar to the VxWorks's example /target/src/drv/intrCtl/ambaIntrCtl.c.
   For the LPC2106,
     - AMBA_INT_CSR_ENB (the "Enable Set" register) is a VICIntEnable register (address-0xFFFFF010)
     - AMBA_INT_CSR_DIS (the "Enable Clear" register) is a VICIntEnClear register (address-0xFFFFF014)
     - AMBA_INT_CSR_PEND (the "Interrupt Request" register) is a VICIRQStatus register (address-0xFFFFF000)


5. System Clocks


  A VxWorks in the minimal configuration needs only the system clock. In the LPC2106 BSP, a Timer 0 is used as a system clock's interrupt source. In the sysClkInt() function the interrupt source should be cleared:


void sysClkInt(void)
{
   rTIMER0_IR = 0xFF;  /* clear interrupt source */
  /* call system clock service routine */
   if(sysClkRoutine != NULL)
      (* sysClkRoutine) (sysClkArg);
}
  

  This is an example of the Timer 0 configuration (the sysClkEnable() function):

void sysClkEnable(void)
{
   if(!sysClkRunning)
   {
        /* Prscaler register and prescaler counter */
      rTIMER0_PR = 0;
      rTIMER0_PC = 0;
        /* Timer counter - to 0 */
      rTIMER0_TC = 0;
        /* Period */
      rTIMER0_MR0 = PRC_CLK / sysClkTicksPerSecond;
        /* clear Timer 0 interrupt source */
      rTIMER0_IR = 0xFF;
      rTIMER0_MCR = 2;  /* bit 1=1 - Reset on MR0 */
        /* Enable Register MR0 Interrupt in the timer */
      rTIMER0_MCR |= 1; /* bit 0=1 -int on MR0 */
        /* Enable the timer(run) */
      rTIMER0_TCR = 1;
        /* enable Timer 0 interrupt in interrupt controller */
      intEnable(INT_LVL_TIMER_0);
      sysClkRunning = TRUE;
   }
}

6. User application

   For the BSP's framework debugging, a very simple user task is used. This task performs just the LED blinking (the file usrAppInit.c in the project directory):

void tLEDBlink(void)
{
   for(;;)
   {
      taskDelay(10);
      rGPIO_IOCLR |= LED_MSK;
      taskDelay(10);
      rGPIO_IOSET |= LED_MSK;
   }
}

void usrAppInit(void)
{
#ifdef   USER_APPL_INIT
    USER_APPL_INIT;           /* for backwards compatibility */
#endif

   int tid;
   tid = taskCreat("tLEDBlink",255, 0, 2048,(FUNCPTR)tLEDBlink,0,0,0,0,0,0,0,0,0,0);
   taskActivate(tid);
}

7. FLASH and RAM usage

   For the test project (LPC2106 in ARM mode, VxWorks 5.5, Tornado 2.2 GNU (GCC 2.9) Compiler):

    - The overall FLASH usage is  ~81 KBytes (no optimization),  ~77 KBytes (optimization: 2)

    - The RAM usage (without the malloc() pool) is  ~11 KBytes