changeset 2886:7c9e64d8c436

* Fix the a problem in the kernel delay_us, if the PIT is initialised later then the period. If the PIT has a big period (after reset) and has to be set to a lower period one has to be sure that the counter is lower then the period value one want to set...
author asl
date Sat, 13 Jun 2009 15:02:52 +0000
parents 361d4d7aa0b3
children 22da989aafa4
files packages/hal/arm/at91/var/current/ChangeLog packages/hal/arm/at91/var/current/src/timer_pit.c
diffstat 2 files changed, 59 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/arm/at91/var/current/ChangeLog
+++ b/packages/hal/arm/at91/var/current/ChangeLog
@@ -1,3 +1,11 @@
+2009-06-03 Oliver Munz <oli@snr.ch>
+
+ 	* Fix the a problem in the kernel delay_us, if the PIT is
+	initialised later then the period. If the PIT has a big
+	period (after reset) and has to be set to a lower period one has
+	to be sure that the counter is lower then the period value one
+	want to set...	
+ 
 2009-05-25  John Dallaway  <john@dallaway.org.uk>
 
 	* include/var_io.h: Provide additional SPI status register defines as
--- a/packages/hal/arm/at91/var/current/src/timer_pit.c
+++ b/packages/hal/arm/at91/var/current/src/timer_pit.c
@@ -41,9 +41,9 @@
 //
 // Author(s):    asl, Oliver Munz
 // Contributors: asl, Oliver Munz
-// Date:         2006-02-12
+// Date:         2009-06-03
 // Purpose:      Clock support using the PIT
-// Description:  
+// Description:
 //
 //####DESCRIPTIONEND####
 //
@@ -59,21 +59,46 @@
 // -------------------------------------------------------------------------
 // Use system clock
 void
-hal_clock_initialize(cyg_uint32 period)
-{
-  cyg_uint32 sr;
+hal_clock_initialize(cyg_uint32 period){
+
+  cyg_uint32 ir;
+  cyg_uint32 pimr;
   
   CYG_ASSERT(CYGNUM_HAL_INTERRUPT_RTC == CYGNUM_HAL_INTERRUPT_PITC,
              "Invalid timer interrupt");
+  CYG_ASSERT(period <= AT91_PITC_VALUE_MASK,
+             "Invalid timer period");
   
-  /* Set Period Interval timer and enable interrupt */
-  HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR), 
-                   (period - 1) |  
-                   AT91_PITC_PIMR_PITEN |
-                   AT91_PITC_PIMR_PITIEN);
+  pimr = (period - 1); /* This is what we want */
+  HAL_READ_UINT32(AT91_PITC + AT91_PITC_PIIR, ir); /* Counter */
+  ir = ir & AT91_PITC_VALUE_MASK; /* The current count */
   
-  // Read the status register to clear any pending interrupt
-  HAL_READ_UINT32(AT91_PITC + AT91_PITC_PISR, sr);
+  do { /* Test if the new PITC-Modulus is overrun by the counter */
+    if (ir > pimr){ /* If the counter is already too high */
+      
+      pimr = (ir + 100) & AT91_PITC_VALUE_MASK; /* Set the comparator ahead */
+      HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR),
+                       pimr | AT91_PITC_PIMR_PITEN);
+    }
+    if (ir < (period - 1)){ /* If we can try it */
+      pimr = (period - 1); /* This is what we want */
+      /* Set the real Period Interval timer */
+      HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR),
+                       pimr | AT91_PITC_PIMR_PITEN);
+    }
+    HAL_READ_UINT32(AT91_PITC + AT91_PITC_PIMR, pimr); /* The real value */
+    pimr = pimr & AT91_PITC_VALUE_MASK; /* Value */
+    HAL_READ_UINT32(AT91_PITC + AT91_PITC_PIIR, ir); /* Counter */
+    ir = ir & AT91_PITC_VALUE_MASK; /* The current counts */
+    
+  } while (ir > (period - 1) || pimr != (period - 1)); // Is it correct?
+  
+  /* Enable interrupt */
+  HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR), (period - 1) |
+                   AT91_PITC_PIMR_PITEN | AT91_PITC_PIMR_PITIEN);
+  
+  /* Read the status register to clear any pending interrupt */
+  HAL_READ_UINT32(AT91_PITC + AT91_PITC_PISR, ir);
 }
 
 // This routine is called during a clock interrupt.
@@ -82,14 +107,14 @@ hal_clock_reset(cyg_uint32 vector, cyg_u
 {
   cyg_uint32 reg;
   cyg_uint32 pimr;
-  
+
   CYG_ASSERT(period < AT91_PITC_VALUE_MASK, "Invalid HAL clock configuration");
-  
+
   // Check that the PIT has the right period.
   HAL_READ_UINT32((AT91_PITC + AT91_PITC_PIMR), pimr);
   if ((pimr & AT91_PITC_VALUE_MASK) != (period - 1)) {
-    HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR), 
-                     (period - 1) |  
+    HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR),
+                     (period - 1) |
                      AT91_PITC_PIMR_PITEN |
                      AT91_PITC_PIMR_PITIEN);
   }
@@ -106,14 +131,14 @@ hal_clock_read(cyg_uint32 *pvalue)
 {
   cyg_uint32 ir;
   cyg_uint32 pimr;
-  
+
   // Check that the PIT is running. If not start it.
   HAL_READ_UINT32((AT91_PITC + AT91_PITC_PIMR),pimr);
   if (!(pimr & AT91_PITC_PIMR_PITEN)) {
-    HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR), 
+    HAL_WRITE_UINT32((AT91_PITC + AT91_PITC_PIMR),
                      AT91_PITC_VALUE_MASK | AT91_PITC_PIMR_PITEN);
   }
-  
+
   HAL_READ_UINT32(AT91_PITC + AT91_PITC_PIIR, ir);
   *pvalue = ir & AT91_PITC_VALUE_MASK;
 }
@@ -128,23 +153,23 @@ void hal_delay_us(cyg_int32 usecs)
   cyg_int64 ticks;
   cyg_uint32 val1, val2;
   cyg_uint32 piv;
-  
+
   // Calculate how many PIT ticks the required number of microseconds
   // equate to. We do this calculation in 64 bit arithmetic to avoid
   // overflow.
-  ticks = (((cyg_uint64)usecs) * 
+  ticks = (((cyg_uint64)usecs) *
            ((cyg_uint64)CYGNUM_HAL_ARM_AT91_CLOCK_SPEED))/16/1000000LL;
-  
-  // Calculate the wrap around period. 
+
+  // Calculate the wrap around period.
   HAL_READ_UINT32(AT91_PITC + AT91_PITC_PIMR, piv);
-  piv = (piv & AT91_PITC_VALUE_MASK) - 1; 
-  
+  piv = (piv & AT91_PITC_VALUE_MASK) - 1;
+
   hal_clock_read(&val1);
   while (ticks > 0) {
     hal_clock_read(&val2);
     if (val2 < val1)
       ticks -= ((piv + val2) - val1); //overflow occurred
-    else 
+    else
       ticks -= (val2 - val1);
     val1 = val2;
   }