added prescaler for 16 bit pwm in LPC1347 target

Fork of mbed-dev by mbed official

Revision:
50:a417edff4437
Parent:
0:9b334a45a8ff
Child:
144:ef7eb2e8f9f7
--- a/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_pcnt.c	Wed Jan 13 12:45:11 2016 +0000
+++ b/targets/hal/TARGET_Silicon_Labs/TARGET_EFM32/emlib/src/em_pcnt.c	Fri Jan 15 07:45:16 2016 +0000
@@ -1,10 +1,10 @@
 /***************************************************************************//**
  * @file em_pcnt.c
  * @brief Pulse Counter (PCNT) peripheral API
- * @version 3.20.12
+ * @version 4.2.1
  *******************************************************************************
  * @section License
- * <b>(C) Copyright 2014 Silicon Labs, http://www.silabs.com</b>
+ * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
  *******************************************************************************
  *
  * Permission is granted to anyone to use this software for any purpose,
@@ -30,13 +30,12 @@
  *
  ******************************************************************************/
 
-
 #include "em_pcnt.h"
 #if defined(PCNT_COUNT) && (PCNT_COUNT > 0)
 
 #include "em_cmu.h"
 #include "em_assert.h"
-#include "em_bitband.h"
+#include "em_bus.h"
 
 /***************************************************************************//**
  * @addtogroup EM_Library
@@ -65,7 +64,7 @@
 #define PCNT_REF_VALID(ref)    (((ref) == PCNT0) || ((ref) == PCNT1) || \
                                 ((ref) == PCNT2))
 #else
-#error Undefined number of pulse counters (PCNT).
+#error "Undefined number of pulse counters (PCNT)."
 #endif
 
 /** @endcond */
@@ -89,7 +88,7 @@
  ******************************************************************************/
 __STATIC_INLINE unsigned int PCNT_Map(PCNT_TypeDef *pcnt)
 {
-  return(((uint32_t)pcnt - PCNT0_BASE) / 0x400);
+  return ((uint32_t)pcnt - PCNT0_BASE) / 0x400;
 }
 
 
@@ -144,10 +143,10 @@
   EFM_ASSERT(PCNT_REF_VALID(pcnt));
 
   /* Enable reset of CNT and TOP register */
-  BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
+  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
 
   /* Disable reset of CNT and TOP register */
-  BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
+  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
 }
 
 
@@ -292,7 +291,7 @@
   pcnt->CTRL = tmp;
 }
 
-#if defined( _PCNT_INPUT_MASK )
+#if defined(_PCNT_INPUT_MASK)
 /***************************************************************************//**
  * @brief
  *   Enable/disable the selected PRS input of PCNT.
@@ -318,26 +317,20 @@
   /* Enable/disable the selected PRS input on the selected PCNT module. */
   switch (prsInput)
   {
-  /* Enable/disable PRS input S0. */
-  case pcntPRSInputS0:
-  {
-    BITBAND_Peripheral(&(pcnt->INPUT), _PCNT_INPUT_S0PRSEN_SHIFT, (uint32_t)enable);
-  }
-  break;
+    /* Enable/disable PRS input S0. */
+    case pcntPRSInputS0:
+      BUS_RegBitWrite(&(pcnt->INPUT), _PCNT_INPUT_S0PRSEN_SHIFT, enable);
+      break;
 
-  /* Enable/disable PRS input S1. */
-  case pcntPRSInputS1:
-  {
-    BITBAND_Peripheral(&(pcnt->INPUT), _PCNT_INPUT_S1PRSEN_SHIFT, (uint32_t)enable);
-  }
-  break;
+    /* Enable/disable PRS input S1. */
+    case pcntPRSInputS1:
+      BUS_RegBitWrite(&(pcnt->INPUT), _PCNT_INPUT_S1PRSEN_SHIFT, enable);
+      break;
 
-  /* Invalid parameter, asserted. */
-  default:
-  {
-    EFM_ASSERT(0);
-  }
-  break;
+    /* Invalid parameter, asserted. */
+    default:
+      EFM_ASSERT(0);
+    break;
   }
 }
 #endif
@@ -448,7 +441,7 @@
     EFM_ASSERT((1<<PCNT0_CNT_SIZE) > init->top);
   }
 #endif
-  
+
 #ifdef PCNT1
   if (PCNT1 == pcnt)
   {
@@ -456,7 +449,7 @@
     EFM_ASSERT((1<<PCNT1_CNT_SIZE) > init->top);
   }
 #endif
-  
+
 #ifdef PCNT2
   if (PCNT2 == pcnt)
   {
@@ -464,11 +457,11 @@
     EFM_ASSERT((1<<PCNT2_CNT_SIZE) > init->top);
   }
 #endif
-  
+
   /* Map pointer to instance */
   inst = PCNT_Map(pcnt);
 
-#if defined( _PCNT_INPUT_MASK )
+#if defined(_PCNT_INPUT_MASK)
   /* Selecting the PRS channels for the PRS input sources of the PCNT. These are
    * written with a Read-Modify-Write sequence in order to keep the value of the
    * input enable bits which can be modified using PCNT_PRSInputEnable(). */
@@ -495,14 +488,14 @@
     tmp |= PCNT_CTRL_FILT;
   }
 
-#if defined( PCNT_CTRL_HYST )
+#if defined(PCNT_CTRL_HYST)
   if (init->hyst)
   {
     tmp |= PCNT_CTRL_HYST;
   }
 #endif
 
-#if defined( PCNT_CTRL_S1CDIR )
+#if defined(PCNT_CTRL_S1CDIR)
   if (init->s1CntDir)
   {
     tmp |= PCNT_CTRL_S1CDIR;
@@ -510,11 +503,11 @@
 #endif
 
   /* Configure counter events for regular and auxiliary counter. */
-#if defined( _PCNT_CTRL_CNTEV_SHIFT )
+#if defined(_PCNT_CTRL_CNTEV_SHIFT)
   tmp |= init->cntEvent << _PCNT_CTRL_CNTEV_SHIFT;
 #endif
 
-#if defined( _PCNT_CTRL_AUXCNTEV_SHIFT )
+#if defined(_PCNT_CTRL_AUXCNTEV_SHIFT)
   {
     /* Modify the auxCntEvent value before writing to the AUXCNTEV field in
        the CTRL register because the AUXCNTEV field values are different from
@@ -524,19 +517,20 @@
     uint32_t auxCntEventField = 0; /* Get rid of compiler warning. */
     switch (init->auxCntEvent)
     {
-    case pcntCntEventBoth:
-      auxCntEventField = pcntCntEventNone;
-      break;
-    case pcntCntEventNone:
-      auxCntEventField = pcntCntEventBoth;
-      break;
-    case pcntCntEventUp:
-    case pcntCntEventDown:
-      auxCntEventField = init->auxCntEvent;
-      break;
-    default:
-      /* Invalid parameter, asserted. */
-      EFM_ASSERT(0);
+      case pcntCntEventBoth:
+        auxCntEventField = pcntCntEventNone;
+        break;
+      case pcntCntEventNone:
+        auxCntEventField = pcntCntEventBoth;
+        break;
+      case pcntCntEventUp:
+      case pcntCntEventDown:
+        auxCntEventField = init->auxCntEvent;
+        break;
+      default:
+        /* Invalid parameter, asserted. */
+        EFM_ASSERT(0);
+        break;
     }
     tmp |= auxCntEventField << _PCNT_CTRL_AUXCNTEV_SHIFT;
   }
@@ -544,7 +538,7 @@
 
   /* Reset pulse counter while changing clock source. The reset bit */
   /* is asynchronous, we don't have to check for SYNCBUSY. */
-  BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
+  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
 
   /* Select LFACLK to clock in control setting */
   CMU_PCNTClockExternalSet(inst, false);
@@ -552,76 +546,76 @@
   /* Handling depends on whether using external clock or not. */
   switch (init->mode)
   {
-  case pcntModeExtSingle:
-  case pcntModeExtQuad:
-    tmp |= init->mode << _PCNT_CTRL_MODE_SHIFT;
+    case pcntModeExtSingle:
+    case pcntModeExtQuad:
+      tmp |= init->mode << _PCNT_CTRL_MODE_SHIFT;
 
-    /* In most cases, the SYNCBUSY bit is set due to reset bit set, and waiting
-     * for asynchronous reset bit is strictly not necessary.
-     * But in theory, other operations on CTRL register may have been done
-     * outside this function, so wait. */
-    PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
+      /* In most cases, the SYNCBUSY bit is set due to reset bit set, and waiting
+       * for asynchronous reset bit is strictly not necessary.
+       * But in theory, other operations on CTRL register may have been done
+       * outside this function, so wait. */
+      PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
 
-    /* Enable PCNT Clock Domain Reset. The PCNT must be in reset before changing
-     * the clock source to an external clock */
-    pcnt->CTRL = PCNT_CTRL_RSTEN;
+      /* Enable PCNT Clock Domain Reset. The PCNT must be in reset before changing
+       * the clock source to an external clock */
+      pcnt->CTRL = PCNT_CTRL_RSTEN;
 
-    /* Wait until CTRL write synchronized into LF domain. */
-    PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
+      /* Wait until CTRL write synchronized into LF domain. */
+      PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
 
-    /* Change to external clock BEFORE disabling reset */
-    CMU_PCNTClockExternalSet(inst, true);
+      /* Change to external clock BEFORE disabling reset */
+      CMU_PCNTClockExternalSet(inst, true);
 
-    /* Write to TOPB. If using external clock TOPB will sync to TOP at the same
-     * time as the mode. This will insure that if the user chooses to count
-     * down, the first "countable" pulse will make CNT go to TOP and not 0xFF
-     * (default TOP value). */
-    pcnt->TOPB = init->top;
+      /* Write to TOPB. If using external clock TOPB will sync to TOP at the same
+       * time as the mode. This will insure that if the user chooses to count
+       * down, the first "countable" pulse will make CNT go to TOP and not 0xFF
+       * (default TOP value). */
+      pcnt->TOPB = init->top;
 
-    /* This bit has no effect on rev. C and onwards parts - for compatibility */
-    pcnt->CMD = PCNT_CMD_LTOPBIM;
+      /* This bit has no effect on rev. C and onwards parts - for compatibility */
+      pcnt->CMD = PCNT_CMD_LTOPBIM;
 
-    /* Write the CTRL register with the configurations.
-     * This should be written after TOPB in the eventuality of a pulse between
-     * these two writes that would cause the CTRL register to be synced one
-     * clock cycle earlier than the TOPB. */
-    pcnt->CTRL = tmp;
+      /* Write the CTRL register with the configurations.
+       * This should be written after TOPB in the eventuality of a pulse between
+       * these two writes that would cause the CTRL register to be synced one
+       * clock cycle earlier than the TOPB. */
+      pcnt->CTRL = tmp;
 
-    /* There are no syncs for TOP, CMD or CTRL because the clock rate is unknown
-     * and the program could stall
-     * These will be synced within 3 clock cycles of the external clock  /
-     * For the same reason CNT cannot be written here. */
-    break;
+      /* There are no syncs for TOP, CMD or CTRL because the clock rate is unknown
+       * and the program could stall
+       * These will be synced within 3 clock cycles of the external clock  /
+       * For the same reason CNT cannot be written here. */
+      break;
 
-  /* pcntModeDisable */
-  /* pcntModeOvsSingle */
-  default:
-    /* No need to set disabled mode if already disabled. */
-    if ((pcnt->CTRL & _PCNT_CTRL_MODE_MASK) != PCNT_CTRL_MODE_DISABLE)
-    {
-      /* Set control to disabled mode, leave reset on until ensured disabled.
-       * We don't need to wait for CTRL SYNCBUSY completion here, it was
-       * triggered by reset bit above, which is asynchronous. */
-      pcnt->CTRL = tmp | PCNT_CTRL_MODE_DISABLE | PCNT_CTRL_RSTEN;
+    /* pcntModeDisable */
+    /* pcntModeOvsSingle */
+    default:
+      /* No need to set disabled mode if already disabled. */
+      if ((pcnt->CTRL & _PCNT_CTRL_MODE_MASK) != PCNT_CTRL_MODE_DISABLE)
+      {
+        /* Set control to disabled mode, leave reset on until ensured disabled.
+         * We don't need to wait for CTRL SYNCBUSY completion here, it was
+         * triggered by reset bit above, which is asynchronous. */
+        pcnt->CTRL = tmp | PCNT_CTRL_MODE_DISABLE | PCNT_CTRL_RSTEN;
 
-      /* Wait until CTRL write synchronized into LF domain before proceeding
-       * to disable reset. */
-      PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
-    }
+        /* Wait until CTRL write synchronized into LF domain before proceeding
+         * to disable reset. */
+        PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
+      }
 
-    /* Disable reset bit, counter should now be in disabled mode. */
-    BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
+      /* Disable reset bit, counter should now be in disabled mode. */
+      BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
 
-    /* Set counter and top values as specified. */
-    PCNT_CounterTopSet(pcnt, init->counter, init->top);
+      /* Set counter and top values as specified. */
+      PCNT_CounterTopSet(pcnt, init->counter, init->top);
 
-    /* Enter oversampling mode if selected. */
-    if (init->mode == pcntModeOvsSingle)
-    {
-      PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
-      pcnt->CTRL = tmp | (init->mode << _PCNT_CTRL_MODE_SHIFT);
-    }
-    break;
+      /* Enter oversampling mode if selected. */
+      if (init->mode == pcntModeOvsSingle)
+      {
+        PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
+        pcnt->CTRL = tmp | (init->mode << _PCNT_CTRL_MODE_SHIFT);
+      }
+      break;
   }
 }
 
@@ -658,7 +652,7 @@
    * modifying RSTEN. The SYNCBUSY bit will be set, leading to a
    * synchronization in the LF domain, with in reality no changes to LF domain.
    * Enable reset of CNT and TOP register. */
-  BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
+  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 1);
 
   /* Select LFACLK as default */
   CMU_PCNTClockExternalSet(inst, false);
@@ -670,7 +664,7 @@
 
   /* Disable reset after CTRL reg has been synchronized */
   PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
-  BITBAND_Peripheral(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
+  BUS_RegBitWrite(&(pcnt->CTRL), _PCNT_CTRL_RSTEN_SHIFT, 0);
 
   /* Clear pending interrupts */
   pcnt->IFC = _PCNT_IFC_MASK;
@@ -678,6 +672,97 @@
   /* Do not reset route register, setting should be done independently */
 }
 
+#if defined(PCNT_OVSCFG_FILTLEN_DEFAULT)
+/***************************************************************************//**
+ * @brief
+ *   Set filter configuration.
+ *
+ * @details
+ *   This function will configure the PCNT input filter, when the PCNT mode is
+ *   configured to take an LFA-derived clock as input clock.
+ *
+ * @param[in] pcnt
+ *   Pointer to PCNT peripheral register block.
+ *
+ * @param[in] config
+ *   Pointer to configuration structure to be applied.
+ *
+ * @param[in] enable
+ *   Whether to enable or disable filtering
+ ******************************************************************************/
+void PCNT_FilterConfiguration(PCNT_TypeDef *pcnt, const PCNT_Filter_TypeDef *config, bool enable) {
+  uint32_t ovscfg = 0;
+  
+  EFM_ASSERT(PCNT_REF_VALID(pcnt));
+  
+  /* Construct new filter setting value */
+  ovscfg  = ((config->filtLen & _PCNT_OVSCFG_FILTLEN_MASK) << _PCNT_OVSCFG_FILTLEN_SHIFT)
+            | ((config->flutterrm & 0x1) << _PCNT_OVSCFG_FLUTTERRM_SHIFT);
+  
+  /* Set new configuration. LF register requires sync check before writing. */
+  PCNT_Sync(pcnt, PCNT_SYNCBUSY_OVSCFG);
+  pcnt->OVSCFG = ovscfg;
+
+  
+  /* Set new state of filter. LF register requires sync check before writing. */
+  PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
+  if(enable) 
+  {
+    pcnt->CTRL |= PCNT_CTRL_FILT;
+  } 
+  else 
+  {
+    pcnt->CTRL &= ~PCNT_CTRL_FILT;
+  }
+}
+#endif
+
+#if defined(PCNT_CTRL_TCCMODE_DEFAULT)
+/***************************************************************************//**
+ * @brief
+ *   Set Triggered Compare and Clear configuration.
+ *
+ * @details
+ *   This function will configure the PCNT TCC (Triggered Compare and Clear)
+ *   module. This module can, upon a configurable trigger source, compare the
+ *   current counter value with the configured TOP value. Upon match, the counter
+ *   will be reset, and the TCC PRS output and TCC interrupt flag will be set.
+ *
+ *   Since there is a comparison with the TOP value, the counter will not stop
+ *   counting nor wrap when hitting the TOP value, but it will keep on counting
+ *   until its maximum value. Then, it will not wrap, but instead stop counting
+ *   and set the overflow flag.
+ *
+ * @param[in] pcnt
+ *   Pointer to PCNT peripheral register block.
+ *
+ * @param[in] config
+ *   Pointer to configuration structure to be applied.
+ ******************************************************************************/
+void PCNT_TCCConfiguration(PCNT_TypeDef *pcnt, const PCNT_TCC_TypeDef *config){
+  uint32_t ctrl = 0;
+  uint32_t mask = _PCNT_CTRL_TCCMODE_MASK
+                  | _PCNT_CTRL_TCCPRESC_MASK
+                  | _PCNT_CTRL_TCCCOMP_MASK
+                  | _PCNT_CTRL_PRSGATEEN_MASK
+                  | _PCNT_CTRL_TCCPRSPOL_MASK
+                  | _PCNT_CTRL_TCCPRSSEL_MASK;
+  
+  EFM_ASSERT(PCNT_REF_VALID(pcnt));
+  
+  /* construct TCC part of configuration register */
+  ctrl |= (config->mode          << _PCNT_CTRL_TCCMODE_SHIFT   ) & _PCNT_CTRL_TCCMODE_MASK;
+  ctrl |= (config->prescaler     << _PCNT_CTRL_TCCPRESC_SHIFT  ) & _PCNT_CTRL_TCCPRESC_MASK;
+  ctrl |= (config->compare       << _PCNT_CTRL_TCCCOMP_SHIFT   ) & _PCNT_CTRL_TCCCOMP_MASK;
+  ctrl |= (config->tccPRS        << _PCNT_CTRL_TCCPRSSEL_SHIFT ) & _PCNT_CTRL_TCCPRSSEL_MASK;
+  ctrl |= (config->prsPolarity   << _PCNT_CTRL_TCCPRSPOL_SHIFT ) & _PCNT_CTRL_TCCPRSPOL_MASK;
+  ctrl |= (config->prsGateEnable << _PCNT_CTRL_PRSGATEEN_SHIFT ) & _PCNT_CTRL_PRSGATEEN_MASK;
+  
+  /* Load new TCC config to PCNT. LF register requires sync check before write. */
+  PCNT_Sync(pcnt, PCNT_SYNCBUSY_CTRL);
+  pcnt->CTRL = (pcnt->CTRL & (~mask)) | ctrl;
+}
+#endif
 
 /***************************************************************************//**
  * @brief
@@ -757,7 +842,6 @@
   pcnt->CMD = PCNT_CMD_LTOPBIM;
 }
 
-
 /** @} (end addtogroup PCNT) */
 /** @} (end addtogroup EM_Library) */
 #endif /* defined(PCNT_COUNT) && (PCNT_COUNT > 0) */