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*/ |
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 -----------------------*/
|
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
|
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