diff options
Diffstat (limited to 'os')
| -rw-r--r-- | os/common/startup/ARMCMx/devices/TM4C123x/cmparams.h | 1 | ||||
| -rw-r--r-- | os/common/startup/ARMCMx/devices/TM4C129x/cmparams.h | 1 | ||||
| -rw-r--r-- | os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.c | 352 | ||||
| -rw-r--r-- | os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.h | 230 | ||||
| -rw-r--r-- | os/hal/ports/TIVA/LLD/uDMA/tiva_udma.h | 2 | ||||
| -rw-r--r-- | os/hal/ports/TIVA/TM4C123x/platform.mk | 1 | ||||
| -rw-r--r-- | os/hal/ports/TIVA/TM4C129x/platform.mk | 1 | 
7 files changed, 587 insertions, 1 deletions
diff --git a/os/common/startup/ARMCMx/devices/TM4C123x/cmparams.h b/os/common/startup/ARMCMx/devices/TM4C123x/cmparams.h index d2693b0..7c40591 100644 --- a/os/common/startup/ARMCMx/devices/TM4C123x/cmparams.h +++ b/os/common/startup/ARMCMx/devices/TM4C123x/cmparams.h @@ -114,6 +114,7 @@ typedef int IRQn_Type;  #include "inc/hw_ssi.h"  #include "inc/hw_udma.h"  #include "inc/hw_pwm.h" +#include "inc/hw_adc.h"  #if CORTEX_NUM_VECTORS != ((((NUM_INTERRUPTS - 16) + 7) / 8) * 8)  #error "TivaWare NUM_INTERRUPTS mismatch" diff --git a/os/common/startup/ARMCMx/devices/TM4C129x/cmparams.h b/os/common/startup/ARMCMx/devices/TM4C129x/cmparams.h index b73032b..7bf68a0 100644 --- a/os/common/startup/ARMCMx/devices/TM4C129x/cmparams.h +++ b/os/common/startup/ARMCMx/devices/TM4C129x/cmparams.h @@ -99,6 +99,7 @@ typedef int IRQn_Type;  #include "inc/hw_ssi.h"  #include "inc/hw_udma.h"  #include "inc/hw_pwm.h" +#include "inc/hw_adc.h"  #if CORTEX_NUM_VECTORS != ((((NUM_INTERRUPTS - 16) + 7) / 8) * 8)  #error "TivaWare NUM_INTERRUPTS mismatch" diff --git a/os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.c b/os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.c new file mode 100644 index 0000000..a175664 --- /dev/null +++ b/os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.c @@ -0,0 +1,352 @@ +/* +    Copyright (C) 2014..2017 Marco Veeneman + +    Licensed under the Apache License, Version 2.0 (the "License"); +    you may not use this file except in compliance with the License. +    You may obtain a copy of the License at + +        http://www.apache.org/licenses/LICENSE-2.0 + +    Unless required by applicable law or agreed to in writing, software +    distributed under the License is distributed on an "AS IS" BASIS, +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +    See the License for the specific language governing permissions and +    limitations under the License. +*/ + +/** + * @file    hal_adc_lld.c + * @brief   PLATFORM ADC subsystem low level driver source. + * + * @addtogroup ADC + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions.                                                 */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables.                                                */ +/*===========================================================================*/ + +/** @brief   ADC0 driver identifier.*/ +#if TIVA_ADC_USE_ADC0 || defined(__DOXYGEN__) +ADCDriver ADCD1; +#endif + +/** @brief   ADC1 driver identifier.*/ +#if TIVA_ADC_USE_ADC1 || defined(__DOXYGEN__) +ADCDriver ADCD2; +#endif + +/*===========================================================================*/ +/* Driver local variables and types.                                         */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions.                                                   */ +/*===========================================================================*/ + +/** + * @brief   Common IRQ handler. + * + * @param[in] adcp      pointer to the @p ADCDriver object + */ +static void serve_interrupt(ADCDriver *adcp) +{ +  uint32_t dmachis = HWREG(UDMA_CHIS); + +  if (dmachis & (1 << adcp->dmanr)) { +    if (adcp->grpp->circular) { +      tiva_udma_table_entry_t *pri = &udmaControlTable.primary[adcp->dmanr]; +      tiva_udma_table_entry_t *alt = &udmaControlTable.alternate[adcp->dmanr]; + +      if ((pri->chctl & UDMA_CHCTL_XFERMODE_M) == UDMA_CHCTL_XFERMODE_STOP) { +        if (adcp->depth > 1) { +          _adc_isr_half_code(adcp); +        } +        else { +          _adc_isr_full_code(adcp); +        } + +        /* Reconfigure DMA for new (lower half) transfer */ +        pri->chctl = adcp->prictl; +      } +      else if ((alt->chctl & UDMA_CHCTL_XFERMODE_M) == UDMA_CHCTL_XFERMODE_STOP) { +        _adc_isr_full_code(adcp); + +        /* Reconfigure DMA for new upper half transfer */ +        alt->chctl = adcp->altctl; +      } +    } +    else { +      /* Transfer complete processing.*/ +      _adc_isr_full_code(adcp); +    } +  } +} + +/*===========================================================================*/ +/* Driver interrupt handlers.                                                */ +/*===========================================================================*/ + +#if TIVA_ADC_USE_ADC0 +/** + * @brief   ADC0 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(TIVA_ADC0_SEQ0_HANDLER) +{ +  OSAL_IRQ_PROLOGUE(); + +  serve_interrupt(&ADCD1); + +  OSAL_IRQ_EPILOGUE(); +} +#endif + +#if TIVA_ADC_USE_ADC1 +/** + * @brief   ADC1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(TIVA_ADC1_SEQ0_HANDLER) +{ +  OSAL_IRQ_PROLOGUE(); + +  serve_interrupt(&ADCD2); + +  OSAL_IRQ_EPILOGUE(); +} +#endif + +/*===========================================================================*/ +/* Driver exported functions.                                                */ +/*===========================================================================*/ + +/** + * @brief   Low level ADC driver initialization. + * + * @notapi + */ +void adc_lld_init(void) +{ +#if TIVA_ADC_USE_ADC0 +  /* Driver initialization.*/ +  adcObjectInit(&ADCD1); +  ADCD1.adc = ADC0_BASE; +  ADCD1.dmanr = TIVA_ADC_ADC0_SS0_UDMA_CHANNEL; +  ADCD1.chnmap = TIVA_ADC_ADC0_SS0_UDMA_MAPPING; +#endif + +#if TIVA_ADC_USE_ADC1 +  /* Driver initialization.*/ +  adcObjectInit(&ADCD2); +  ADCD2.adc = ADC1_BASE; +  ADCD2.dmanr = TIVA_ADC_ADC1_SS0_UDMA_CHANNEL; +  ADCD2.chnmap = TIVA_ADC_ADC1_SS0_UDMA_MAPPING; +#endif +} + +/** + * @brief   Configures and activates the ADC peripheral. + * + * @param[in] adcp      pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start(ADCDriver *adcp) +{ +  if (adcp->state == ADC_STOP) { +    /* Enables the peripheral.*/ +#if TIVA_ADC_USE_ADC0 +    if (&ADCD1 == adcp) { +      bool b; +      b = udmaChannelAllocate(adcp->dmanr); +      osalDbgAssert(!b, "channel already allocated"); + +      HWREG(SYSCTL_RCGCADC) |= (1 << 0); + +      while (!(HWREG(SYSCTL_PRADC) & (1 << 0))) +        ; + +      /* Only sequencer 0 is supported */ +      nvicEnableVector(TIVA_ADC0_SEQ0_NUMBER, TIVA_ADC0_SEQ0_PRIORITY); +    } +#endif + +#if TIVA_ADC_USE_ADC1 +    if (&ADCD2 == adcp) { +      bool b; +      b = udmaChannelAllocate(adcp->dmanr); +      osalDbgAssert(!b, "channel already allocated"); + +      HWREG(SYSCTL_RCGCADC) |= (1 << 1); + +      while (!(HWREG(SYSCTL_PRADC) & (1 << 1))) +        ; + +      /* Only sequencer 0 is supported */ +      nvicEnableVector(TIVA_ADC1_SEQ0_NUMBER, TIVA_ADC1_SEQ0_PRIORITY); +    } +#endif + +    HWREG(UDMA_CHMAP0 + (adcp->dmanr / 8) * 4) |= (adcp->chnmap << (adcp->dmanr % 8)); +  } +} + +/** + * @brief   Deactivates the ADC peripheral. + * + * @param[in] adcp      pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop(ADCDriver *adcp) +{ +  if (adcp->state == ADC_READY) { +    /* Resets the peripheral.*/ + +    /* Disables the peripheral.*/ +#if TIVA_ADC_USE_ADC0 +    if (&ADCD1 == adcp) { + +    } +#endif + +#if TIVA_ADC_USE_ADC1 +    if (&ADCD2 == adcp) { + +    } +#endif +  } +} + +/** + * @brief   Starts an ADC conversion. + * + * @param[in] adcp      pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_start_conversion(ADCDriver *adcp) +{ +  uint32_t adc = adcp->adc; +  tiva_udma_table_entry_t *primary = &udmaControlTable.primary[adcp->dmanr]; +  tiva_udma_table_entry_t *alternate = &udmaControlTable.alternate[adcp->dmanr]; + +  /* Disable sample sequencer 0 */ +  HWREG(adc + ADC_O_ACTSS) &= (1 << 0); + +  /* Configure the sample sequencer 0 trigger */ +  HWREG(adc + ADC_O_EMUX) = adcp->grpp->emux & 0xff; + +  /* If pwm is used as trigger, select in which block the pwm generator is +     located */ +  if (adcp->grpp->emux >= 6 && adcp->grpp->emux <= 9) { +    HWREG(adc + ADC_O_TSSEL) = 0; +  } + +  /* For each sample in the sample sequencer, select the input source */ +  HWREG(adc + ADC_O_SSMUX0) = adcp->grpp->ssmux; + +  /* Configure the sample control bits */ +  HWREG(adc + ADC_O_SSCTL0) = adcp->grpp->ssctl | 0x44444444; /* Enforce IEn bits */ + +  /* Primary source endpoint is the same for all transfers */ +  primary->srcendp = (void *)(adcp->adc + ADC_O_SSFIFO0); + +  /* Configure DMA */ +  if ((adcp->grpp->circular) && (adcp->depth > 1)) { +    /* Configure DMA in ping-pong mode. +       Ping (1st half) is configured in the primary control structure. +       Pong (2nd half) is configured in the alternate control structure. */ + +    uint32_t ctl; + +    /* configure the alternate source endpoint */ +    alternate->srcendp = (void *)(adcp->adc + ADC_O_SSFIFO0); + +    /* sample buffer is split in half, the upper half is used here */ +    primary->dstendp = (void *)(adcp->samples + +                               (adcp->grpp->num_channels * adcp->depth / 2) - 1); +    /* the lower half is used here */ +    alternate->dstendp = (void *)(adcp->samples + +                                 (adcp->grpp->num_channels * adcp->depth) - 1); + +    ctl = UDMA_CHCTL_DSTSIZE_32 | UDMA_CHCTL_DSTINC_32 | +          UDMA_CHCTL_SRCSIZE_32 | UDMA_CHCTL_SRCINC_NONE | +          UDMA_CHCTL_ARBSIZE_1 | +          UDMA_CHCTL_XFERSIZE(adcp->grpp->num_channels * adcp->depth / 2) | +          UDMA_CHCTL_XFERMODE_PINGPONG; + +    adcp->prictl = ctl; +    adcp->altctl = ctl; +  } +  else { +    /* Configure the DMA in basic mode. +       This is used for both circular buffers with a depth of 1 and linear +       buffers.*/ +    primary->dstendp = (void *)(adcp->samples + +                               (adcp->grpp->num_channels * adcp->depth) - 1); +    adcp->prictl = UDMA_CHCTL_DSTSIZE_32 | UDMA_CHCTL_DSTINC_32 | +                   UDMA_CHCTL_SRCSIZE_32 | UDMA_CHCTL_SRCINC_NONE | +                   UDMA_CHCTL_ARBSIZE_1 | +                   UDMA_CHCTL_XFERSIZE(adcp->grpp->num_channels * adcp->depth) | +                   UDMA_CHCTL_XFERMODE_BASIC; +    adcp->altctl = UDMA_CHCTL_XFERMODE_STOP; +  } + +  /* Configure primary and alternate channel control fields */ +  primary->chctl = adcp->prictl; +  alternate->chctl = adcp->altctl; + +  /* Configure DMA channel */ +  dmaChannelPrimary(adcp->dmanr); +  dmaChannelBurstOnly(adcp->dmanr); +  dmaChannelPriorityDefault(adcp->dmanr); +  dmaChannelEnableRequest(adcp->dmanr); + +  /* Enable DMA channel */ +  dmaChannelEnable(adcp->dmanr); + +  /* Enable the sample sequencer */ +  HWREG(adc + ADC_O_ACTSS) |= (1 << 0); + +  /* Enable DMA on the sample sequencer, is this for 129x only?*/ +  //HWREG(adc + ADC_O_ACTSS) |= (1 << 8); + +  /* Start conversion if configured for CPU trigger */ +  if ((adcp->grpp->emux & 0xff) == 0) { +    HWREG(adc + ADC_O_PSSI) = ADC_PSSI_SS0; +  } +} + +/** + * @brief   Stops an ongoing conversion. + * + * @param[in] adcp      pointer to the @p ADCDriver object + * + * @notapi + */ +void adc_lld_stop_conversion(ADCDriver *adcp) +{ +  uint32_t adc = adcp->adc; + +  /* Stop ongoing DMA transfer */ +  dmaChannelDisable(adcp->dmanr); + +  /* Stop ongoing ADC conversion by disabling the active sample sequencer */ +  HWREG(adc + ADC_O_ACTSS) &= ~(1 << 0); +} + +#endif /* HAL_USE_ADC == TRUE */ + +/** @} */ diff --git a/os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.h b/os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.h new file mode 100644 index 0000000..81916b8 --- /dev/null +++ b/os/hal/ports/TIVA/LLD/ADC/hal_adc_lld.h @@ -0,0 +1,230 @@ +/* +    Copyright (C) 2014..2017 Marco Veeneman + +    Licensed under the Apache License, Version 2.0 (the "License"); +    you may not use this file except in compliance with the License. +    You may obtain a copy of the License at + +        http://www.apache.org/licenses/LICENSE-2.0 + +    Unless required by applicable law or agreed to in writing, software +    distributed under the License is distributed on an "AS IS" BASIS, +    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +    See the License for the specific language governing permissions and +    limitations under the License. +*/ + +/** + * @file    hal_adc_lld.h + * @brief   PLATFORM ADC subsystem low level driver header. + * + * @addtogroup ADC + * @{ + */ + +#ifndef HAL_ADC_LLD_H +#define HAL_ADC_LLD_H + +#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants.                                                         */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings.                                         */ +/*===========================================================================*/ + +/** + * @name    PLATFORM configuration options + * @{ + */ +/** + * @brief   ADC1 driver enable switch. + * @details If set to @p TRUE the support for ADC1 is included. + * @note    The default is @p FALSE. + */ +#if !defined(PLATFORM_ADC_USE_ADC1) || defined(__DOXYGEN__) +#define PLATFORM_ADC_USE_ADC1                  FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks.                                       */ +/*===========================================================================*/ + +#if !defined(TIVA_UDMA_REQUIRED) +#define TIVA_UDMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types.                                         */ +/*===========================================================================*/ + +/** + * @brief   ADC sample data type. + */ +typedef uint32_t adcsample_t; + +/** + * @brief   Channels number in a conversion group. + */ +typedef uint16_t adc_channels_num_t; + +/** + * @brief   Possible ADC failure causes. + * @note    Error codes are architecture dependent and should not relied + *          upon. + */ +typedef enum { +  ADC_ERR_DMAFAILURE = 0,                   /**< DMA operations failure.    */ +  ADC_ERR_OVERFLOW = 1,                     /**< ADC overflow condition.    */ +  ADC_ERR_AWD = 2                           /**< Analog watchdog triggered. */ +} adcerror_t; + +/** + * @brief   Type of a structure representing an ADC driver. + */ +typedef struct ADCDriver ADCDriver; + +/** + * @brief   ADC notification callback type. + * + * @param[in] adcp      pointer to the @p ADCDriver object triggering the + *                      callback + * @param[in] buffer    pointer to the most recent samples data + * @param[in] n         number of buffer rows available starting from @p buffer + */ +typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n); + +/** + * @brief   ADC error callback type. + * + * @param[in] adcp      pointer to the @p ADCDriver object triggering the + *                      callback + * @param[in] err       ADC error code + */ +typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err); + +/** + * @brief   Conversion group configuration structure. + * @details This implementation-dependent structure describes a conversion + *          operation. + * @note    The use of this configuration structure requires knowledge of + *          PLATFORM ADC cell registers interface, please refer to the PLATFORM + *          reference manual for details. + */ +typedef struct { +  /** +   * @brief   Enables the circular buffer mode for the group. +   */ +  bool                      circular; +  /** +   * @brief   Number of the analog channels belonging to the conversion group. +   */ +  adc_channels_num_t        num_channels; +  /** +   * @brief   Callback function associated to the group or @p NULL. +   */ +  adccallback_t             end_cb; +  /** +   * @brief   Error callback or @p NULL. +   */ +  adcerrorcallback_t        error_cb; +  /* End of the mandatory fields.*/ +  uint32_t                  emux; +  uint32_t                  ssmux; +  uint32_t                  ssctl; +} ADCConversionGroup; + +/** + * @brief   Driver configuration structure. + * @note    It could be empty on some architectures. + */ +typedef struct { +  uint32_t                  dummy; +} ADCConfig; + +/** + * @brief   Structure representing an ADC driver. + */ +struct ADCDriver { +  /** +   * @brief Driver state. +   */ +  adcstate_t                state; +  /** +   * @brief Current configuration data. +   */ +  const ADCConfig           *config; +  /** +   * @brief Current samples buffer pointer or @p NULL. +   */ +  adcsample_t               *samples; +  /** +   * @brief Current samples buffer depth or @p 0. +   */ +  size_t                    depth; +  /** +   * @brief Current conversion group pointer or @p NULL. +   */ +  const ADCConversionGroup  *grpp; +#if (ADC_USE_WAIT == TRUE) || defined(__DOXYGEN__) +  /** +   * @brief Waiting thread. +   */ +  thread_reference_t        thread; +#endif +#if (ADC_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__) +  /** +   * @brief Mutex protecting the peripheral. +   */ +  mutex_t                   mutex; +#endif +#if defined(ADC_DRIVER_EXT_FIELDS) +  ADC_DRIVER_EXT_FIELDS +#endif +  /* End of the mandatory fields.*/ +  /** +   * @brief Pointer to the ADC registers block. +   */ +  uint32_t                  adc; +  uint8_t                   dmanr; +  uint8_t                   chnmap; +  uint32_t                  prictl; +  uint32_t                  altctl; +}; + +/*===========================================================================*/ +/* Driver macros.                                                            */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations.                                                    */ +/*===========================================================================*/ + +#if TIVA_ADC_USE_ADC0 && !defined(__DOXYGEN__) +extern ADCDriver ADCD1; +#endif + +#if TIVA_ADC_USE_ADC1 && !defined(__DOXYGEN__) +extern ADCDriver ADCD2; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +  void adc_lld_init(void); +  void adc_lld_start(ADCDriver *adcp); +  void adc_lld_stop(ADCDriver *adcp); +  void adc_lld_start_conversion(ADCDriver *adcp); +  void adc_lld_stop_conversion(ADCDriver *adcp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_ADC == TRUE */ + +#endif /* HAL_ADC_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/TIVA/LLD/uDMA/tiva_udma.h b/os/hal/ports/TIVA/LLD/uDMA/tiva_udma.h index cf90399..a473f6c 100644 --- a/os/hal/ports/TIVA/LLD/uDMA/tiva_udma.h +++ b/os/hal/ports/TIVA/LLD/uDMA/tiva_udma.h @@ -32,7 +32,7 @@  /**   * @brief   CHCTL XFERSIZE helper.   */ -#define UDMA_CHCTL_XFERSIZE(n)          ((n-1) << 4) +#define UDMA_CHCTL_XFERSIZE(n)          (((n)-1) << 4)  /*===========================================================================*/  /* Driver pre-compile time settings.                                         */ diff --git a/os/hal/ports/TIVA/TM4C123x/platform.mk b/os/hal/ports/TIVA/TM4C123x/platform.mk index 2544696..de482d0 100644 --- a/os/hal/ports/TIVA/TM4C123x/platform.mk +++ b/os/hal/ports/TIVA/TM4C123x/platform.mk @@ -11,6 +11,7 @@ HALCONF := $(strip $(shell cat halconf.h | egrep -e "\#define"))  endif  # Drivers compatible with the platform. +include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/ADC/driver.mk  include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/GPIO/driver.mk  include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/GPTM/driver.mk  include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/I2C/driver.mk diff --git a/os/hal/ports/TIVA/TM4C129x/platform.mk b/os/hal/ports/TIVA/TM4C129x/platform.mk index fb2dc4a..8e4c9fa 100644 --- a/os/hal/ports/TIVA/TM4C129x/platform.mk +++ b/os/hal/ports/TIVA/TM4C129x/platform.mk @@ -11,6 +11,7 @@ HALCONF := $(strip $(shell cat halconf.h | egrep -e "\#define"))  endif  # Drivers compatible with the platform. +include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/ADC/driver.mk  include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/GPIO/driver.mk  include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/GPTM/driver.mk  include $(CHIBIOS_CONTRIB)/os/hal/ports/TIVA/LLD/I2C/driver.mk  | 
