changeset 2586:b147c0c67463

* cdl/hal_arm_lpc24xx.cdl: Added configuration options for ADC clock and RTC clock * include/lpc24xx_misc.h Added macros CYG_HAL_ARM_LPC24XX_PCLK() and CYG_HAL_ARM_LPC24XX_SET_POWER() for configuring on-chip peripherals Added CYG_HAL_ARM_LPC24XX_PIN_CFG() for configuration of pin function * src/lpc24xx_misc.c: Changed function hal_delay_us() to use the same timer (timer 0) like the eCos realtime clock. This safes one timer peripheral for application use. Fixed wrong clock divider table in hal_lpc_set_pclk(). Added ADC and RTC clock divider configuration and power on.
author asl
date Tue, 04 Nov 2008 16:19:37 +0000
parents 2f250a337a5e
children 2f467aabb085
files packages/hal/arm/lpc24xx/var/current/ChangeLog packages/hal/arm/lpc24xx/var/current/cdl/hal_arm_lpc24xx.cdl packages/hal/arm/lpc24xx/var/current/include/lpc24xx_misc.h packages/hal/arm/lpc24xx/var/current/include/var_io.h packages/hal/arm/lpc24xx/var/current/src/lpc24xx_misc.c
diffstat 5 files changed, 217 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/arm/lpc24xx/var/current/ChangeLog
+++ b/packages/hal/arm/lpc24xx/var/current/ChangeLog
@@ -1,3 +1,16 @@
+2008-11-01  Uwe Kindler  <uwe_kindler@web.de>
+
+	* cdl/hal_arm_lpc24xx.cdl: Added configuration options for ADC
+	  clock and RTC clock
+	* include/lpc24xx_misc.h Added macros CYG_HAL_ARM_LPC24XX_PCLK() and
+	  CYG_HAL_ARM_LPC24XX_SET_POWER() for configuring on-chip peripherals
+	  Added CYG_HAL_ARM_LPC24XX_PIN_CFG() for configuration of pin function
+	* src/lpc24xx_misc.c: Changed function hal_delay_us() to use the same
+	  timer (timer 0) like the eCos realtime clock. This safes one timer
+	  peripheral for application use. 
+	  Fixed wrong clock divider table in hal_lpc_set_pclk(). Added ADC and
+	  RTC clock divider configuration and power on.
+	  
 2008-09-18  Uwe Kindler  <uwe_kindler@web.de>
 
 	* cdl/hal_arm_lpc24xx.cdl: Added I2C configuration options for
--- a/packages/hal/arm/lpc24xx/var/current/cdl/hal_arm_lpc24xx.cdl
+++ b/packages/hal/arm/lpc24xx/var/current/cdl/hal_arm_lpc24xx.cdl
@@ -241,15 +241,17 @@ cdl_package CYGPKG_HAL_ARM_LPC24XX {
                 legal_values  1 to 8
                 default_value { 6 }
                 description "
-                    This divider controls the division of the PLL output before 
-                    it is used by the USB block. If the PLL is bypassed, the 
-                    division may be by 1. In that case, the PLL input frequency 
-                    must be 48 MHz, with a 500 ppm tolerance. When the PLL is 
-                    running, the output must be divided in order to bring the 
-                    USB clock frequency to 48 MHz with a 50% duty cycle. A 
-                    4-bit divider allows obtaining the correct USB clock from 
-                    any even multiple of 48 MHz (i.e. any mutliple of 96 MHz) 
-                    within the PLL operating range."
+                    This divider controls the division of the PLL
+                    output before it is used by the USB block. If the
+                    PLL is bypassed, the division may be by 1. In that
+                    case, the PLL input frequency must be 48 MHz, with
+                    a 500 ppm tolerance. When the PLL is running, the
+                    output must be divided in order to bring the USB
+                    clock frequency to 48 MHz with a 50% duty cycle. A
+                    4-bit divider allows obtaining the correct USB
+                    clock from any even multiple of 48 MHz (i.e. any
+                    mutliple of 96 MHz) within the PLL operating
+                    range."
             }
         }
         
@@ -274,7 +276,49 @@ cdl_package CYGPKG_HAL_ARM_LPC24XX {
             }
         }
         
-        for { set ::channel 0 } { $::channel < 3 } { incr ::channel } { 
+        cdl_component CYGNUM_HAL_ARM_LPC24XX_RTC_CLK {
+            display       "RTC clock speed"
+            flavor        data
+            calculated   {  CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / 
+                            CYGNUM_HAL_ARM_LPC24XX_RTC_CLK_DIV}
+            description "
+                The RTC clock speed is the CPU clock output divided by the 
+                RTC clock divider" 
+                
+            cdl_option CYGNUM_HAL_ARM_LPC24XX_RTC_CLK_DIV {
+                display       "RTC clock divider"
+                flavor        data
+                legal_values  { 2 4 8 }
+                default_value { 2 }
+                description "
+                    This divider selects the peripheral clock for on-chip 
+                    RTC if no external 32.768 kHz crystal clock for the 
+                    on-chip real-time clock peripheral unit is provided."
+            }
+        }
+        
+        cdl_component CYGNUM_HAL_ARM_LPC24XX_ADC_CLK {
+            display       "ADC clock speed"
+            flavor        data
+            calculated   {  CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / 
+                            CYGNUM_HAL_ARM_LPC24XX_ADC_CLK_DIV}
+            description "
+                The ADC clock speed is the CPU clock output divided by the 
+                ADC clock divider" 
+                
+            cdl_option CYGNUM_HAL_ARM_LPC24XX_ADC_CLK_DIV {
+                display       "ADC clock divider"
+                flavor        data
+                legal_values  { 1 2 4 8 }
+                default_value { 1 }
+                description "
+                    This divider selects the peripheral clock for on-chip 
+                    ADC. The ADC clock is the input clock of the ADC 
+                    peripheral."
+            }
+        }
+        
+        for { set ::channel 0 } { $::channel < 3 } { incr ::channel } {            
             cdl_component CYGNUM_HAL_ARM_LPC24XX_I2C[set ::channel]_CLK {
                 display       "I2C channel [set ::channel] clock speed"
                 flavor        data
@@ -302,6 +346,7 @@ cdl_package CYGPKG_HAL_ARM_LPC24XX {
         cdl_component CYGHWR_HAL_ARM_LPC24XX_I2C[set ::channel]_SUPP {
             display       "I2C channel [set ::channel] configuration"
             parent        CYGPKG_DEVS_I2C_ARM_LPC2XXX
+            active_if     CYGPKG_DEVS_I2C_ARM_LPC2XXX
             flavor         bool
             default_value  [set ::channel] == 0
             description "
@@ -319,7 +364,7 @@ cdl_package CYGPKG_HAL_ARM_LPC24XX {
                     interrupt priority registers defaults all
                     interrupts to the lowest priority 15, allowing a
                     single write to elevate the priority of an
-                    individual interrupt."  
+                    individual interrupt."
             }
         
             cdl_option CYGNUM_HAL_ARM_LPC24XX_I2C[set ::channel]_BUS_FREQ {
--- a/packages/hal/arm/lpc24xx/var/current/include/lpc24xx_misc.h
+++ b/packages/hal/arm/lpc24xx/var/current/include/lpc24xx_misc.h
@@ -55,6 +55,7 @@
 // Use PCLK identifiers below
 //
 externC cyg_uint32 hal_lpc_get_pclk(cyg_uint32 pclk_id);
+#define CYG_HAL_ARM_LPC24XX_PCLK(_pclkid_) hal_lpc_get_pclk(_pclkid_) 
 
 //
 // Identifiers for peripheral clock. Use these identifiers with the function
@@ -96,6 +97,9 @@ externC cyg_uint32 hal_lpc_get_pclk(cyg_
 // Use PCONP identifiers from below
 //
 externC void hal_lpc_set_power(cyg_uint8 pconp_id, int on);
+#define CYG_HAL_ARM_LPC24XX_SET_POWER(_pconp_id_, _on_) \
+        hal_lpc_set_power((_pconp_id_), (_on_))
+
 
 //
 // Identifiers for power control
@@ -133,7 +137,10 @@ externC void hal_lpc_set_power(cyg_uint8
 //-----------------------------------------------------------------------------
 // Configure pin function
 //
-void hal_set_pin_function(cyg_uint8 port, cyg_uint8 pin, cyg_uint8 function);
+externC void hal_set_pin_function(cyg_uint8 port, cyg_uint8 pin, 
+                                  cyg_uint8 function);
+#define CYG_HAL_ARM_LPC24XX_PIN_CFG(_port_, _pin_, _func_) \
+        hal_set_pin_function((_port_), (_pin_), (_func_))
 
 
 //-----------------------------------------------------------------------------
@@ -143,7 +150,6 @@ void hal_set_pin_function(cyg_uint8 port
 // Now we rely on the fact that we use the same baudrate clock for all
 // UARTs and we query only UART0
 //-----------------------------------------------------------------------------
-#define CYG_HAL_ARM_LPC24XX_PCLK(_pclkid_) hal_lpc_get_pclk(_pclkid_) 
 #define CYG_HAL_ARM_LPC2XXX_BAUD_GENERATOR(baud) \
             (CYG_HAL_ARM_LPC24XX_PCLK(CYNUM_HAL_LPC24XX_PCLK_UART0)/((baud)*16))
 #define CYG_HAL_ARM_LPC24XX_BAUD_GENERATOR(_pclkid_, baud) \
--- a/packages/hal/arm/lpc24xx/var/current/include/var_io.h
+++ b/packages/hal/arm/lpc24xx/var/current/include/var_io.h
@@ -351,6 +351,8 @@
 // RTC
 
 #define CYGARC_HAL_LPC24XX_REG_RTC_BASE                   0xE0024000
+#define CYGARC_HAL_LPC2XXX_REG_RTC_BASE                   0xE0024000 
+
 
 // Registers are offsets from base of this subsystem
 
@@ -483,8 +485,8 @@
 
 //=============================================================================
 // ADC (AD)
-
 #define CYGARC_HAL_LPC24XX_REG_AD_BASE                  0xE0034000
+#define CYGARC_HAL_LPC2XXX_REG_AD_BASE CYGARC_HAL_LPC24XX_REG_AD_BASE
 
 // Registers are offsets from base of this subsystem
 #define CYGARC_HAL_LPC24XX_REG_ADCR                     0x0000
--- a/packages/hal/arm/lpc24xx/var/current/src/lpc24xx_misc.c
+++ b/packages/hal/arm/lpc24xx/var/current/src/lpc24xx_misc.c
@@ -75,6 +75,9 @@
 #include <cyg/infra/diag.h>     // For diagnostic printing
 
 
+static cyg_uint32 clock_period = 0;
+
+
 //===========================================================================
 // Get peripheral clock for a certain peripheral
 //===========================================================================
@@ -115,9 +118,13 @@ cyg_uint32 hal_lpc_get_pclk(cyg_uint32 p
 //===========================================================================
 void hal_lpc_set_pclk(cyg_uint32 peripheral_id, cyg_uint8 divider)
 {
-    static const cyg_uint8 clock_tbl[4] =
+    static const cyg_uint8 clock_tbl[5] =
     {
-        0x01, 0x02, 0x00, 0x03
+        0x01, // divider 1
+        0x02, // divider 2 
+        0x00, // divider 4
+        0x03, // divider 6
+        0x03  // divider 8
     }; 
     cyg_uint32 clock;
     cyg_uint32 pclkselreg;
@@ -134,7 +141,6 @@ void hal_lpc_set_pclk(cyg_uint32 periphe
                   CYGARC_HAL_LPC24XX_REG_PCLKSEL0 : 
                   CYGARC_HAL_LPC24XX_REG_PCLKSEL1;  
     HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_SCB_BASE + pclkselreg, regval);
-    divider = (6 == divider) ? 8 : divider;
     clock = clock_tbl[divider >> 1];
     regval &= ~(0x03 << ((peripheral_id & 0xF) << 1));
     regval |= (clock << ((peripheral_id & 0xF) << 1));   
@@ -189,30 +195,61 @@ void hal_set_pin_function(cyg_uint8 port
 
 
 //===========================================================================
+// Start clock of RTC timer
+//===========================================================================
+void hal_start_clock_tmr(cyg_uint32 period)
+{
+    if (clock_period == period)
+    {
+        return;
+    }
+
+
+    cyg_uint32 tmr_period = period / (CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / 
+                            hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER0)); 
+    
+    //
+    // Execute the following steps only if counter is not running yet
+    //                        
+    if (!clock_period)
+    {    
+        // 
+        // Disable and reset counter, set prescale register to 0 and
+        // Set up match register 
+        //
+        HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                         CYGARC_HAL_LPC24XX_REG_TxTCR, 2);
+        HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                         CYGARC_HAL_LPC24XX_REG_TxPR, 0);
+    }
+    
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                     CYGARC_HAL_LPC24XX_REG_TxMR0, tmr_period);  
+    //
+    // Reset on match and Enable counter - interrupts are disabled
+    //
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                     CYGARC_HAL_LPC24XX_REG_TxMCR, 
+                     CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET);
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                     CYGARC_HAL_LPC24XX_REG_TxTCR, 1); 
+}
+
+
+//===========================================================================
 // initialize timer 0 as eCos realtime clock source
 //===========================================================================
 void hal_clock_initialize(cyg_uint32 period)
 {
-    CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
-
-    period = period / (CYGNUM_HAL_ARM_LPC24XX_CLOCK_SPEED / 
-                       hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER0));
-
-    // 
-    // Disable and reset counter, set prescale register to 0 and
-    // Set up match register 
-    //
-    HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxTCR, 2);
-    HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxPR, 0);
-    HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxMR0, period);
+    hal_start_clock_tmr(period);
     
     //
-    // Reset and generate interrupt on match and Enable counter
+    // Reset and generate interrupt on match
     //
-    HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxMCR, 
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                     CYGARC_HAL_LPC24XX_REG_TxMCR, 
                      CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_INT | 
                      CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET);
-    HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 1);
 }
 
 
@@ -221,22 +258,20 @@ void hal_clock_initialize(cyg_uint32 per
 //===========================================================================
 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
 {
-    static cyg_uint32 _period = 0;
-    CYG_ADDRESS        timer  = CYGARC_HAL_LPC24XX_REG_TIMER0_BASE;
-
-    HAL_WRITE_UINT32(timer + CYGARC_HAL_LPC24XX_REG_TxIR, 
+    HAL_WRITE_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                     CYGARC_HAL_LPC24XX_REG_TxIR, 
                      CYGARC_HAL_LPC24XX_REG_TxIR_MR0);  // Clear interrupt
 
-    if (period != _period) 
+    if (period != clock_period) 
     {
         hal_clock_initialize(period);
     }
-    _period = period;
+    clock_period = period;
 }
 
 
 //===========================================================================
-// Reset clock value
+// Read clock value
 //===========================================================================
 void hal_clock_read(cyg_uint32 *pvalue)
 {
@@ -249,40 +284,77 @@ void hal_clock_read(cyg_uint32 *pvalue)
 
 
 //===========================================================================
-// Delay for some number of micro-seconds - use TIMER1
+// Delay for maximum 1000 micorseconds
 //===========================================================================
-void hal_delay_us(cyg_int32 usecs)
+static void delay_max1000_us(cyg_uint32 usecs)
 {
-    CYG_ADDRESS timer = CYGARC_HAL_LPC24XX_REG_TIMER1_BASE;
-    cyg_uint32 stat;
-    cyg_uint64 ticks;
+    cyg_uint32 ticks;
+    cyg_uint32 start_counter;
+    cyg_uint32 target_counter;
+    cyg_uint32 counter;
+    cyg_uint32 tmr_period;
+      
 
+    CYG_ASSERT((usecs <= 1000) && (usecs > 0), "Invalid usecs value");
+    HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                    CYGARC_HAL_LPC24XX_REG_TxTC, start_counter);
+                    
+    HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                    CYGARC_HAL_LPC24XX_REG_TxMR0, tmr_period);
+                   
+    //
+    // If timer 0 match period is not initialized, then this is the
+    // first time that someone uses the timer and we need to initialize it
+    //
+    if (!tmr_period)
+    {
+        hal_start_clock_tmr(CYGNUM_HAL_RTC_PERIOD);
+        HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                        CYGARC_HAL_LPC24XX_REG_TxMR0, tmr_period);
+    } 
+                                        
     // Calculate how many timer ticks the required number of
     // microseconds equate to. We do this calculation in 64 bit
     // arithmetic to avoid overflow.
     ticks = (((cyg_uint64)usecs) * 
-             ((cyg_uint64)hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER1))) / 
+             ((cyg_uint64)hal_lpc_get_pclk(CYNUM_HAL_LPC24XX_PCLK_TIMER0))) / 
                1000000LL;
-    
-    // Disable and reset counter
-    HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 2);
+               
+    target_counter = (start_counter + ticks) % tmr_period;
     
-    // Stop on match
-    HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxMR0, ticks);
-    HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxMCR, 
-                     CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_STOP | 
-                     CYGARC_HAL_LPC24XX_REG_TxMCR_MR0_RESET);
+    if (target_counter > start_counter)
+    {
+        do
+        {
+            HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                            CYGARC_HAL_LPC24XX_REG_TxTC, counter);
+        } while ((counter >= start_counter) && (counter < target_counter));
+    }
+    else
+    {
+        do
+        {
+            HAL_READ_UINT32(CYGARC_HAL_LPC24XX_REG_TIMER0_BASE + 
+                            CYGARC_HAL_LPC24XX_REG_TxTC, counter);
+        } while ((counter >= start_counter) || (counter < target_counter));
+    } // if (target_counter > start_counter)
+}
 
-    //set prescale register to 0
-    HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxPR, 0);         
 
-    // Enable counter
-    HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTCR, 1);
+//===========================================================================
+// Delay for a certain numbr of microseconds
+//===========================================================================
+void hal_delay_us(cyg_int32 usecs)
+{   
+    cyg_uint16 delay_duration = usecs % 1000;
+    delay_duration = (delay_duration != 0) ? delay_duration : 1000;
 
-    // Wait for the match
-    do {
-        HAL_READ_UINT32(timer+CYGARC_HAL_LPC24XX_REG_TxTC, stat);
-    } while (stat < ticks);
+    do
+    {
+        delay_max1000_us(delay_duration); 
+        usecs -= delay_duration;
+        delay_duration = 1000;   
+    } while (usecs > 0);  
 }
 
 
@@ -309,6 +381,10 @@ void hal_hardware_init(void)
                      CYGNUM_HAL_ARM_LPC24XX_I2C1_CLK_DIV);
     hal_lpc_set_pclk(CYNUM_HAL_LPC24XX_PCLK_I2C2,  
                      CYGNUM_HAL_ARM_LPC24XX_I2C2_CLK_DIV);
+    hal_lpc_set_pclk(CYNUM_HAL_LPC24XX_PCLK_RTC,  
+                     CYGNUM_HAL_ARM_LPC24XX_RTC_CLK_DIV);
+    hal_lpc_set_pclk(CYNUM_HAL_LPC24XX_PCLK_ADC,  
+                     CYGNUM_HAL_ARM_LPC24XX_ADC_CLK_DIV);
                      
     //
     // Enable power for all used on-chip peripherals
@@ -329,7 +405,20 @@ void hal_hardware_init(void)
     hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_I2C2, 1);
 #else
     hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_I2C2, 0);
-#endif // CYGHWR_HAL_ARM_LPC24XX_I2C0_SUPP    
+#endif // CYGHWR_HAL_ARM_LPC24XX_I2C0_SUPP  
+ 
+#ifdef CYGPKG_DEVICES_WALLCLOCK_ARM_LPC2XXX
+    hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_RTC, 1);
+#else 
+    hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_RTC, 0);
+#endif // CYGPKG_DEVICES_WALLCLOCK_ARM_LPC2XXX
+
+#ifdef CYGPKG_DEVS_ADC_ARM_LPC24XX
+    hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_ADC, 1);
+    hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_TIMER1, 1);
+#else
+    hal_lpc_set_power(CYNUM_HAL_LPC24XX_PCONP_ADC, 0);
+#endif // CYGPKG_DEVS_ADC_ARM_LPC24XX
     
     //
     // Fill vector address registers with interrupt number. If an interrupt