Mercurial > ecos
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; } //--------------------------------------------------------------------------
