changeset 2187:2d74b1f822f7

* cdl/hal_arm_lpc2xxx.cdl: Added CYGHWR_HAL_ARM_LPC2XXX_FAMILY, CYGNUM_HAL_ARM_LPC2XXX_VPBDIV, CYGNUM_HAL_ARM_LPC2XXX_XCLKDIV and CYGHWR_HAL_ARM_LPC2XXX_IDLE_PWRSAVE. Changed CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA to a bool. * include/hal_var_ints.h: Removed lpc2xxx misc functions and added an include for lpc2xxx_misc.h to avoid breaking things. * include/lpc2xxx_misc.h: New header file for all the lpc2xxx miscellaneous functions. * include/var_arch.h: Made idle powerdown CDL controlled. * include/var_io.h: Changed to use family CDL variables. * src/lpc2xxx_misc.c: Changes to interrupt and VPBDIV code.
author asl
date Sun, 07 May 2006 18:36:18 +0000
parents 60d13514f34b
children 33a63029a5f8
files packages/hal/arm/lpc2xxx/var/current/ChangeLog packages/hal/arm/lpc2xxx/var/current/cdl/hal_arm_lpc2xxx.cdl packages/hal/arm/lpc2xxx/var/current/include/hal_var_ints.h packages/hal/arm/lpc2xxx/var/current/include/lpc2xxx_misc.h packages/hal/arm/lpc2xxx/var/current/include/var_arch.h packages/hal/arm/lpc2xxx/var/current/include/var_io.h packages/hal/arm/lpc2xxx/var/current/src/lpc2xxx_misc.c
diffstat 7 files changed, 361 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/arm/lpc2xxx/var/current/ChangeLog
+++ b/packages/hal/arm/lpc2xxx/var/current/ChangeLog
@@ -1,3 +1,17 @@
+2006-02-14  Andy Jackson <andy@grapevinetech.co.uk>
+
+	* cdl/hal_arm_lpc2xxx.cdl: Added CYGHWR_HAL_ARM_LPC2XXX_FAMILY,
+	CYGNUM_HAL_ARM_LPC2XXX_VPBDIV, CYGNUM_HAL_ARM_LPC2XXX_XCLKDIV
+	and CYGHWR_HAL_ARM_LPC2XXX_IDLE_PWRSAVE. Changed 
+	CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA to a bool.
+	* include/hal_var_ints.h: Removed lpc2xxx misc functions and
+	added an include for lpc2xxx_misc.h to avoid breaking things.
+	* include/lpc2xxx_misc.h: New header file for all the lpc2xxx
+	miscellaneous functions.
+	* include/var_arch.h: Made idle powerdown CDL controlled.
+	* include/var_io.h: Changed to use family CDL variables.
+	* src/lpc2xxx_misc.c: Changes to interrupt and VPBDIV code.
+
 2004-09-12  Jani Monoses <jani@iv.ro>
 
 	* src/hal_diag.c: 
--- a/packages/hal/arm/lpc2xxx/var/current/cdl/hal_arm_lpc2xxx.cdl
+++ b/packages/hal/arm/lpc2xxx/var/current/cdl/hal_arm_lpc2xxx.cdl
@@ -73,20 +73,70 @@ cdl_package CYGPKG_HAL_ARM_LPC2XXX {
         puts $::cdl_system_header "#define CYGBLD_HAL_ARM_VAR_ARCH_H"
     }
 
-    cdl_option CYGHWR_HAL_ARM_LPC2XXX {
+    # This is going to get really messy before long as the number of parts
+    # explodes. Its useful to know the actual part in use, but its just as
+    # useful to know which family it belongs to. LPC210x shouldn't really
+    # be in the list of devices, but will probably break something if removed.
+    cdl_component CYGHWR_HAL_ARM_LPC2XXX {
         display        "LPC2XXX variant used"
         flavor         data
-        default_value  {"LPC210x"}
-        legal_values   {"LPC210x" 
-			"LPC2114" "LPC2119" "LPC2124" "LPC2129" "LPC2132" 
-                        "LPC2138" "LPC2194" "LPC2212" "LPC2214" "LPC2290" 
-                        "LPC2292" "LPC2294"}
+        default_value  { "LPC210x" }
+        legal_values   { "LPC210x"
+                "LPC2101" "LPC2102" "LPC2103" "LPC2104" "LPC2105" "LPC2106"
+                "LPC2114" "LPC2119" "LPC2124" "LPC2129" "LPC2131" "LPC2132" 
+                "LPC2134" "LPC2136" "LPC2138" "LPC2141" "LPC2142" "LPC2144"
+                "LPC2146" "LPC2148" "LPC2194" "LPC2210" "LPC2212" "LPC2214"
+                "LPC2220" "LPC2290" "LPC2292" "LPC2294" }
+        description    "
+             The LPC2XXX microcontroller family has several variants,
+             the main differences being the amount of on-chip RAM,
+             flash and peripherals. This option allows the platform
+             HALs to select the specific microcontroller being used."
 
-        description    "The LPC2XXX microcontroller family has several
-                        variants, the main differences being the amount of 
-                        on-chip RAM, flash and peripherals. This option allows 
-                        the platform HALs to select the specific 
-                        microcontroller being used."
+        cdl_option CYGHWR_HAL_ARM_LPC2XXX_FAMILY {
+            display       "LPC2XXX variant family"
+            flavor        data
+            calculated    {
+                is_substr(CYGHWR_HAL_ARM_LPC2XXX, "LPC22") ? "LPC22XX" :
+                is_substr(CYGHWR_HAL_ARM_LPC2XXX, "LPC213") ? "LPC213X" :
+                is_substr(CYGHWR_HAL_ARM_LPC2XXX, "LPC214") ? "LPC214X" :
+                is_substr(CYGHWR_HAL_ARM_LPC2XXX, "LPC210") ? "LPC210X" :
+                "LPC21XX"
+                          }
+            description   "
+                This specifies the family that the processor
+                belongs to. This is useful as it defines certain common
+                characteristics (e.g lpc22xx has the external bus and
+                lpc214x has USB) which affect which features should be
+                available in the HAL."
+        }
+    }
+
+    cdl_option CYGNUM_HAL_ARM_LPC2XXX_VPBDIV {
+        display       "VPB clock divisor"
+        flavor        data
+        legal_values  { 4 2 1 }
+        default_value { 4 }
+        description   "
+            This option sets the divisor for the VPB clock relative to
+            the processor clock. 4 means that the VPB clock runs at
+            one fourth the processor clock, 2 means that it runs at
+            one half of the processor clock and 1 means that it is the
+            same as the processor clock."
+    }
+
+    cdl_option CYGNUM_HAL_ARM_LPC2XXX_XCLKDIV {
+        display         "XCLK clock divisor"
+        flavor          data
+        legal_values    { 4 2 1 }
+        default_value   { 4 }
+        active_if       { CYGHWR_HAL_ARM_LPC2XXX_FAMILY == "LPC22XX" }
+        description     "
+            This option sets the divisor for the XCLK clock relative
+            to the processor clock. 4 means that the XCLK clock runs
+            at one fourth the processor clock, 2 means that it runs at
+            one half of the processor clock and 1 means that it is the
+            same as the processor clock."
     }
 
     cdl_component CYGNUM_HAL_RTC_CONSTANTS {
@@ -111,13 +161,31 @@ cdl_package CYGPKG_HAL_ARM_LPC2XXX {
         }
     }
    
+    # Enable this by default, as I believe it won't affect parts that
+    # don't have the problem (other than slowing them down slightly)
+    # but causes a lock-up on those that do...
     cdl_option CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA {
         display       "EXTINT.1 errata workaround"
-	flavor        data	       
-	default_value 0	       
-        description    "On some chips writing to the EXTPOLAR or EXTMODE 
-                        registers while VPBDIV is non-zero can corrupt the 
-                        latter. Also reading them will yield incorrect values.
-		        Enable this option to work around the problem."
+        flavor        bool       
+        default_value 1           
+        description   "
+
+            On some chips writing to the EXTPOLAR or EXTMODE registers
+            while VPBDIV is non-zero can corrupt the latter. Also
+            reading them will yield incorrect values.  Enable this
+            option to work around the problem."  
+    }
+
+    cdl_option CYGHWR_HAL_ARM_LPC2XXX_IDLE_PWRSAVE {
+        display       "Stop clock in idle loop to save power"
+        flavor        bool
+        default_value { is_active(CYGPKG_REDBOOT) ? 0 : 1 }
+        description   "
+           Select this option when it is desired to save power by
+           stoping the processor clock in the idle loop. This is
+           controlled by the PCON register. Generally this is a good
+           thing, but it may be necessary to disable this when
+           debugging via JTAG, as stopping the clock can prevent the
+           debugger getting control of the system."
     }
 }
--- a/packages/hal/arm/lpc2xxx/var/current/include/hal_var_ints.h
+++ b/packages/hal/arm/lpc2xxx/var/current/include/hal_var_ints.h
@@ -95,16 +95,11 @@
 
 #define CYGNUM_HAL_ISR_COUNT         (CYGNUM_HAL_ISR_MAX+1)
 
-__externC cyg_uint32 hal_lpc_get_pclk(void);
-#define CYG_HAL_ARM_LPC2XXX_PCLK() hal_lpc_get_pclk() 
-#define CYG_HAL_ARM_LPC2XXX_BAUD_GENERATOR(baud) \
-            (CYG_HAL_ARM_LPC2XXX_PCLK()/((baud)*16))
-
 //The vector used by the Real time clock
 #define CYGNUM_HAL_INTERRUPT_RTC     CYGNUM_HAL_INTERRUPT_TIMER0
 
-__externC void hal_lpc_watchdog_reset(void);
-#define HAL_PLATFORM_RESET() hal_lpc_watchdog_reset()
-#define HAL_PLATFORM_RESET_ENTRY 0
+// Other entries here moved to variant specific include file
+// This is included here to avoid breaking anything
+#include <cyg/hal/lpc2xxx_misc.h>
 
 #endif // CYGONCE_HAL_VAR_INTS_H
new file mode 100644
--- /dev/null
+++ b/packages/hal/arm/lpc2xxx/var/current/include/lpc2xxx_misc.h
@@ -0,0 +1,77 @@
+#ifndef CYGONCE_HAL_ARM_LPC2XXX_VAR_LPC2XXX_MISC_H
+#define CYGONCE_HAL_ARM_LPC2XXX_VAR_LPC2XXX_MISC_H
+//=============================================================================
+//
+//      lpc2xxx_misc.h
+//
+//      HAL misc variant support code for Philips LPC2xxx header file
+//
+//=============================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2006 eCosCentric Limited 
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//=============================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    andyj 
+// Contributors: jani
+// Date:         2006-02-04
+// Purpose:      LPC2XXX specific miscellaneous support header file
+// Description: 
+// Usage:        #include <cyg/hal/lpc2xxx_misc.h>
+//
+//####DESCRIPTIONEND####
+//
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Functions to obtain the current processor clock settings
+//-----------------------------------------------------------------------------
+externC cyg_uint32 hal_lpc_get_cclk(void);
+externC cyg_uint32 hal_lpc_get_pclk(void);
+externC cyg_uint32 hal_lpc_get_xclk(void);
+
+//-----------------------------------------------------------------------------
+// Macros to derive the baudrate divider values for the internal UARTs
+//-----------------------------------------------------------------------------
+#define CYG_HAL_ARM_LPC2XXX_PCLK() hal_lpc_get_pclk() 
+#define CYG_HAL_ARM_LPC2XXX_BAUD_GENERATOR(baud) \
+            (CYG_HAL_ARM_LPC2XXX_PCLK()/((baud)*16))
+
+//-----------------------------------------------------------------------------
+// LPX2xxx watchdog support
+//-----------------------------------------------------------------------------
+externC void hal_lpc_watchdog_reset(void);
+
+#define HAL_PLATFORM_RESET() hal_lpc_watchdog_reset()
+#define HAL_PLATFORM_RESET_ENTRY 0
+
+//-----------------------------------------------------------------------------
+// end of lpc2xxx_misc.h
+#endif // CYGONCE_HAL_ARM_LPC2XXX_VAR_LPC2XXX_MISC_H
--- a/packages/hal/arm/lpc2xxx/var/current/include/var_arch.h
+++ b/packages/hal/arm/lpc2xxx/var/current/include/var_arch.h
@@ -59,9 +59,10 @@
 // chance to insert code. Typical idle thread behaviour might be to halt the
 // processor. These implementations halt the system core clock.
 
+#ifdef CYGHWR_HAL_ARM_LPC2XXX_IDLE_PWRSAVE
+
 #ifndef HAL_IDLE_THREAD_ACTION
 
-
 #define HAL_IDLE_THREAD_ACTION(_count_)                       \
 CYG_MACRO_START                                               \
 HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +            \
@@ -69,8 +70,9 @@ HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_
                  CYGARC_HAL_LPC2XXX_REG_PCON_IDL);            \
 CYG_MACRO_END
 
+#endif		// HAL_IDLE_THREAD_ACTION
 
-#endif
+#endif		// CYGHWR_HAL_ARM_LPC2XXX_IDLE_MODE
 
 //-----------------------------------------------------------------------------
 // end of var_arch.h
--- a/packages/hal/arm/lpc2xxx/var/current/include/var_io.h
+++ b/packages/hal/arm/lpc2xxx/var/current/include/var_io.h
@@ -374,8 +374,7 @@
 
 #define CYGARC_HAL_LPC2XXX_REG_IO_BASE                   0xE0028000
 
-
-#if defined(CYGHWR_HAL_ARM_LPC2XXX_LPC210x)
+#if defined(CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC210X)
 
 // Registers are offsets from base of this subsystem
 #define CYGARC_HAL_LPC2XXX_REG_IOPIN                     0x000
@@ -494,8 +493,7 @@
 //=============================================================================
 // External Memory Controller
 
-#if defined(CYGHWR_HAL_ARM_LPC2XXX_LPC2212) || \
-    defined(CYGHWR_HAL_ARM_LPC2XXX_LPC2214)
+#if defined(CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX)
 
 #define CYGARC_HAL_LPC2XXX_REG_BCFG0                    0xFFE00000
 #define CYGARC_HAL_LPC2XXX_REG_BCFG1                    0xFFE00004
--- a/packages/hal/arm/lpc2xxx/var/current/src/lpc2xxx_misc.c
+++ b/packages/hal/arm/lpc2xxx/var/current/src/lpc2xxx_misc.c
@@ -50,6 +50,7 @@
 //========================================================================*/
 
 #include <pkgconf/hal.h>
+#include <pkgconf/hal_arm_lpc2xxx.h>
 
 #include <cyg/infra/cyg_type.h>         // base types
 #include <cyg/infra/cyg_trac.h>         // tracing macros
@@ -67,17 +68,33 @@
 #endif
 #include <cyg/hal/var_io.h>             // platform registers
 
-static cyg_uint32 lpc_cclk;	//CPU clock frequency
-static cyg_uint32 lpc_pclk;	//peripheral devices clock speed
-                                //(equal to, half, or quarter of CPU
-                                //clock)
+#include <cyg/infra/diag.h>     // For diagnostic printing
+
+// -------------------------------------------------------------------------
+// Processor clock configuration values and accessor functions
+static cyg_uint32 lpc_cclk; // CPU clock frequency
+static cyg_uint32 lpc_pclk; // peripheral devices clock speed
+                            // (equal to, half, or quarter of CPU clock)
+static cyg_uint32 lpc_xclk; // XCLK speed (equal to, half, or quarter of
+                            // CPU clock)
+
+cyg_uint32 hal_lpc_get_cclk(void)
+{
+    return (lpc_cclk); 
+}
 
 cyg_uint32 hal_lpc_get_pclk(void)
 {
-    return lpc_pclk; 
+    return (lpc_pclk); 
 }
+
+cyg_uint32 hal_lpc_get_xclk(void)
+{
+    return (lpc_xclk); 
+}
+
 // -------------------------------------------------------------------------
-// Clock support
+// eCos clock support
 // Use TIMER0
 static cyg_uint32 _period;
 
@@ -172,35 +189,53 @@ void hal_delay_us(cyg_int32 usecs)
 // we need to read twice consecutively to get correct value
 cyg_uint32 lpc_get_vpbdiv(void)
 {   
-    cyg_uint32 div;	
-    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                    CYGARC_HAL_LPC2XXX_REG_VPBDIV, div);
+    cyg_uint32 vpbdiv_reg;
+	
     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                    CYGARC_HAL_LPC2XXX_REG_VPBDIV, div);
+                    CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv_reg);
+    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                    CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv_reg);
 
-    return div;
+    return (vpbdiv_reg);
 }
 
-//Set the two bits in VPBDIV which control peripheral clock division
-//div must be 1,2 or 4
-void lpc_set_vpbdiv(int div)
-{   
-    cyg_uint8 orig = lpc_get_vpbdiv();
+// Set the VPBDIV register. The vpb bits are 1:0 and the xclk bits are 5:4. The
+// mapping of values passed to this routine to field values is:
+//		4 = divide by 4 (register bits 00)
+//		2 = divide by 2 (register bits 10)
+//		1 = divide by 1 (register bits 01)
+// This routine assumes that only these values can occur. As they are
+// generated in the CDL hopefully this should be the case. Fortunately
+// writing 11 merely causes the previous value to be retained.
+void lpc_set_vpbdiv(int vpbdiv, int xclkdiv)
+{
+    CYG_ASSERT(((vpbdiv & 0x3) != 3) && ((xclkdiv & 0x3) != 3),
+               "illegal VPBDIV register value");
+
+    // Update VPBDIV register
+#ifdef CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV,
+                     ((xclkdiv & 0x3) << 4) | (vpbdiv & 0x3));
+#else
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv & 0x3);
+#endif
     
-    // update VPBDIV register
-    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, (div % 4) | (orig & 0xFC));
-    
-    lpc_pclk = lpc_cclk/div;
+    lpc_pclk = lpc_cclk / vpbdiv;
+    lpc_xclk = lpc_cclk / xclkdiv;
 }
 
+// Perform variant setup
 void hal_hardware_init(void)
 {
     lpc_cclk = CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED;
-    lpc_set_vpbdiv(4);
+#ifdef CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX
+    lpc_set_vpbdiv(CYGNUM_HAL_ARM_LPC2XXX_VPBDIV,
+                   CYGNUM_HAL_ARM_LPC2XXX_XCLKDIV);
+#endif
     // Set up eCos/ROM interfaces
     hal_if_init();
-
 }
 
 // -------------------------------------------------------------------------
@@ -208,104 +243,178 @@ void hal_hardware_init(void)
 // should interrogate the hardware and return the IRQ vector number.
 int hal_IRQ_handler(void)
 {
-    cyg_uint32 irq_num,irq_stat;
-    // Find out which interrupt caused the IRQ
-    // picks the lowest if there are more.
+    cyg_uint32 irq_num, irq_stat;
+
+    // Find out which interrupt caused the IRQ. This picks the lowest
+    // if there are more than 1.
     // FIXME:try to make use of the VIC for better latency.
     //       That will probably need changes to vectors.S and 
     //       other int-related code
     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
                     CYGARC_HAL_LPC2XXX_REG_VICIRQSTAT, irq_stat);
     for (irq_num = 0; irq_num < 32; irq_num++)
-	    if (irq_stat & (1<<irq_num)) break;
-    // No valid interrrupt source, treat as spurious interrupt    
+      if (irq_stat & (1 << irq_num))
+        break;
+    
+    // If not a valid interrrupt source, treat as spurious interrupt    
     if (irq_num < CYGNUM_HAL_ISR_MIN || irq_num > CYGNUM_HAL_ISR_MAX)
       irq_num = CYGNUM_HAL_INTERRUPT_NONE;
     
-    return irq_num;
+    return (irq_num);
 }
 
 // -------------------------------------------------------------------------
 // Interrupt control
 //
 
+// Block the the interrupt associated with the vector
 void hal_interrupt_mask(int vector)
 {
     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
 
     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
-                     CYGARC_HAL_LPC2XXX_REG_VICINTENCLEAR, 1<<vector);
+                     CYGARC_HAL_LPC2XXX_REG_VICINTENCLEAR, 1 << vector);
 }
 
+// Unblock the the interrupt associated with the vector
 void hal_interrupt_unmask(int vector)
 {
     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
 
     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
-                     CYGARC_HAL_LPC2XXX_REG_VICINTENABLE, 1<<vector);
+                     CYGARC_HAL_LPC2XXX_REG_VICINTENABLE, 1 << vector);
 }
 
+// Acknowledge the the interrupt associated with the vector. This
+// clears the interrupt but may result in another interrupt being
+// delivered
 void hal_interrupt_acknowledge(int vector)
 {
+
+    // External interrupts have to be cleared from the EXTINT register
+    if (vector >= CYGNUM_HAL_INTERRUPT_EINT0 &&
+        vector <= CYGNUM_HAL_INTERRUPT_EINT3)
+      {
+        // Map int vector to corresponding bit (0..3)
+        vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
+        
+        // Clear the external interrupt
+        HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                         CYGARC_HAL_LPC2XXX_REG_EXTINT, vector);
+      }
+    
+    //
     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
                      CYGARC_HAL_LPC2XXX_REG_VICVECTADDR, 0);  
 }
 
+// This provides control over how an interrupt signal is detected.
+// Options are between level or edge sensitive (level) and high/low
+// level or rising/falling edge triggered (up).
+//
+// This should be simple, but unfortunately on some processor revisions,
+// it trips up on two errata issues (for the LPC2294 Rev.A these are
+// EXTINT.1 and VPBDIV.1) and so on these devices a somewhat convoluted
+// sequence in order to work properly. There is nothing in the errata
+// sequence that won't work on a processor without these issues.
 void hal_interrupt_configure(int vector, int level, int up)
 {
-    cyg_uint32 mode;
-    cyg_uint32 pol;
-    // only external interrupts are configurable	
+    cyg_uint32 regval, saved_vpbdiv;
+
+    // Only external interrupts are configurable	
     CYG_ASSERT(vector <= CYGNUM_HAL_INTERRUPT_EINT3 &&
                vector >= CYGNUM_HAL_INTERRUPT_EINT0 , "Invalid vector");
-#if CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA
-    // Errata sheet says VPBDIV is corrupted when accessing EXTPOL or EXTMOD
-    // Must be written as 0 and at the end restored to original value
-    
-    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
-#endif    
-    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                    CYGARC_HAL_LPC2XXX_REG_EXTMODE, mode);
-    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                    CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, pol);
-    
-    // map int vector to corresponding bit (0..3)
+
+    // Map int vector to corresponding bit (0..3)
     vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
     
-    // level or edge
-    if (level) {
-	mode &= ~vector;   
-    } else {
-	mode |= vector;   
-    }
+#ifdef CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA
+    // From discussions with the Philips applications engineers on the
+    // Yahoo LPC2000 forum, it appears that in order up change both
+    // EXTMODE and EXTPOLAR, the operations have to be performed in
+    // two passes as follows:
+    // old=VPBDIV (x2),
+    //     VPBDIV=0, EXTMODE=n, VPBDIV=n, VPBDIV=0, EXTPOLAR=y, VPBDIV=y
+    // VPCDIV=old
+    
+    // Save current VPBDIV register settings
+    saved_vpbdiv = lpc_get_vpbdiv();
+    
+    // Clear VPBDIV register
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
+    
+    // Read current mode and update for level (0) or edge detection (1)
+    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                    CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
+    if (level)
+      regval &= ~vector;
+    else
+      regval |= vector;
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
+    
+    // Set VPBDIV register to same value as mode
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, regval);
+    
+    // Clear VPBDIV register
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
     
-    // high/low or falling/rising
-    if (up) {
-	pol |= vector;   
-    } else {
-	pol &= ~vector;   
-    }
+    // Read current polarity and update for trigger level or edge
+    // level: high (1), low (0) edge: rising (1), falling (0)
+    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                    CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
+    if (up)
+      regval |= vector;
+    else
+      regval &= ~vector;
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
     
+    // Set VPBDIV register to same value as mode
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, regval);
+    
+    // Restore saved VPBDIV register
     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                     CYGARC_HAL_LPC2XXX_REG_EXTMODE, mode);
+                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, saved_vpbdiv);
+#else
+    // Read current mode and update for level (0) or edge detection (1)
+    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                    CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
+    if (level)
+      regval &= ~vector;
+    else
+      regval |= vector;
     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
-                     CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, pol);
+                     CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
     
-#if CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA    
-    // we know this was the original value
-    lpc_set_vpbdiv(lpc_cclk/lpc_pclk);
+    // Read current polarity and update for trigger level or edge
+    // level: high (1), low (0) edge: rising (1), falling (0)
+    HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                    CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
+    if (up)
+      regval |= vector;
+    else
+      regval &= ~vector;
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
 #endif
+    // Clear any spurious interrupt that might have been generated
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
+                     CYGARC_HAL_LPC2XXX_REG_EXTINT, vector);
 }
 
+// Change interrupt level. This is a non-operation on the LPC2XXX
 void hal_interrupt_set_level(int vector, int level)
 {
     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
     CYG_ASSERT(level >= 0 && level <= 15, "Invalid level");
-
 }
 
 // Use the watchdog to generate a reset
@@ -326,7 +435,8 @@ void hal_lpc_watchdog_reset(void)
                      CYGARC_HAL_LPC2XXX_REG_WDFEED, 
                      CYGARC_HAL_LPC2XXX_REG_WDFEED_MAGIC2);
     
-    while(1);
+    while(1)
+      continue;
 }
 
 //--------------------------------------------------------------------------