⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lh79524_adc_driver.c

📁 LH79524SoftwareLH79524 Software
💻 C
📖 第 1 页 / 共 4 页
字号:
/***********************************************************************
 * $Workfile:   lh79524_adc_driver.c  $
 * $Revision:   1.0  $
 * $Author:   ZhangJ  $
 * $Date:   Oct 20 2004 09:48:54  $
 *
 * Project: LH79524 ADC driver
 *
 * Description:
 *     This file contains driver support for the ADC module on the
 *     LH79524
 *
 * Notes:
 *     The number of different configurations supported by the ADC
 *     is beyond the scope of this driver. This driver provides the
 *     following basic functions:
 *         Sequenced analog to digital conversions (polled, interrupt)
 *         Touchscreen conversions (polled, interrupt)
 *         Pendown state detect to touchscreen conversions (interrupt)
 *         Brownout interrupt handling (interrupt only)
 *         ADC status polling and general configuration
 *
 * Revision History:
 * $Log::   //smaicnt2/pvcs/VM/sharpmcu/archives/sharpmcu/software/csps$
 * 
 *    Rev 1.0   Oct 20 2004 09:48:54   ZhangJ
 * Initial revision.
 * 
 *    Rev 1.1   Jul 20 2004 16:50:32   PattamattaD
 * Updated comments.
 * 
 *    Rev 1.0   Jun 25 2004 14:26:02   PattamattaD
 * Initial revision.
 * 
 * 
 * 
 ***********************************************************************
 * 
 *  Copyright (c) 2004 Sharp Microelectronics of the Americas 
 * 
 *  All rights reserved 
 * 
 *  SHARP MICROELECTRONICS OF THE AMERICAS MAKES NO REPRESENTATION 
 *  OR WARRANTIES WITH RESPECT TO THE PERFORMANCE OF THIS SOFTWARE, 
 *  AND SPECIFICALLY DISCLAIMS ANY RESPONSIBILITY FOR ANY DAMAGES, 
 *  SPECIAL OR CONSEQUENTIAL, CONNECTED WITH THE USE OF THIS SOFTWARE. 
 * 
 *  SHARP MICROELECTRONICS OF THE AMERICAS PROVIDES THIS SOFTWARE SOLELY
 *  FOR THE PURPOSE OF SOFTWARE DEVELOPMENT INCORPORATING THE USE OF A 
 *  SHARP MICROCONTROLLER OR SYSTEM-ON-CHIP PRODUCT. USE OF THIS SOURCE 
 *  FILE IMPLIES ACCEPTANCE OF THESE CONDITIONS. 
 * 
 *********************************************************************/

#include "lh79524_adc_driver.h"
#include "lh79524_rcpc.h"
#include "lh79524_iocon.h"

/***********************************************************************
* ADC driver private data and types
**********************************************************************/

/* Size of the ADC receive ring buffer */
#define ADC_RING_BUFSIZE 64

/* Function prototype used for polled and interrupt driven reads */
typedef INT_32 (*ADC_RFUNC_T) (void *, void *, INT_32);

/* ADC device configuration structure type */
typedef struct
{
  BOOL_32 init;       /* Device initialized flag */
  ADC_REGS_T *regptr; /* Pointer to ADC registers */
  UNS_16 rx[ADC_RING_BUFSIZE];  /* ADC data ring buffer */
  INT_32 rx_head;     /* ADC ring buffer head index */
  INT_32 rx_tail;     /* ADC ring buffer tail index */
  UNS_16 conv_count;  /* Number of conversions to perform */
  PFV bro_cbfunc;     /* Brown interrupt callback function */
  PFV pd_cbfunc;      /* Pendown interrupt completion callback
												 function */
  PFV eos_cbfunc;     /* End of sequence interrupt callback
												 function */
  UNS_32 adc_clk_source; /* clock coming to ADC block from RCPC */
} ADC_CFG_T;

/* ADC device configuration structure */
static ADC_CFG_T adccfg;

/***********************************************************************
* ADC driver private functions
**********************************************************************/
/*********************************************************************** 
* 
* Function: adc_get_clock
* 
* Purpose: 
*  Return the ADC's time base in Hz
* 
* Processing: 
*  Compute the time base using the system clock and the divider.
* 
* Parameters: 
*     adccfgptr:     Pointer to ADC config structure
* 
* Outputs: None. 
* 
* Returns: 
*  the actual base frequency in Hz or _ERROR if the frequency is 
*  out of range for the converter or the system clock.
* 
* Notes: None
* 
**********************************************************************/ 
static UNS_32 adc_get_clock(ADC_CFG_T* adccfgptr)
{
  UNS_32 freq;        
  
  freq = adccfgptr->adc_clk_source /
    (1 << ADC_CLKSEL_GET(adccfgptr->regptr->adcpcr));
  
  if (freq < ADC_MIN_CLK || freq > ADC_MAX_CLK)
    return 0;
  
  return freq;
}

/*********************************************************************** 
* 
* Function: adc_set_clock
* 
* Purpose: 
*  Set the ADC's time base
* 
* Processing: 
*  Use the system clock and the divider to get as close as possible
*  without going outside the min and max operating frequency of the
*  ADC.
* 
* Parameters: 
*  freq:				the desired base frequency in Hz
*  adccfgptr:   Pointer to ADC config structure
* 
* Outputs: None. 
* 
* Returns: 
*  the actual base frequency in Hz or _ERROR if a legal frequency is
*  not obtainable using the system clock.
* 
* Notes: 
*  If the requested frequency is too high, the maximum frequency
*  is returned. If the requested frequency is too low, the minimum
*  frequency is returned. If the requested frequency, even after
*  clipping it to be in range, cannot be generated using the system
*  clock, then this function returns _ERROR. This implies that the
*  system clock is too high or too low to use the ADC.
* 
**********************************************************************/ 
static UNS_32 adc_set_clock(UNS_32 freq, ADC_CFG_T* adccfgptr)
{
  /* clk is the freq. of the clock that drives the ADC block, in Hz */
  INT_32 clk;
  INT_32 divisor_idx;      /* the power of 2 of the current divisor */
  INT_32 best_divisor_idx; /* the value of divisor_idx for best_delta*/
  INT_32 divisor;          /* 1 << divisor_idx*/
  INT_32 new_freq;         /* clk / divisor*/
  INT_32 delta;            /* abs(new_freq - freq)*/
  INT_32 best_delta;       /* the smallest value of delta found so far*/
  UNS_32 temp;             /* intermediate value of the PC register*/
  /* max_clk is the highest value of freq the ADC can handle */
  INT_32 max_clk = (ADC_MAX_CLK < adccfgptr->adc_clk_source) ? 
                    ADC_MAX_CLK : adccfgptr->adc_clk_source;
  
  if (freq > max_clk)
    freq = max_clk;
  if (freq < ADC_MIN_CLK)
    freq = ADC_MIN_CLK;
  
  clk = adccfgptr->adc_clk_source;
  
  best_divisor_idx = 0;
  best_delta = freq - clk;
  if (best_delta < 0)
    best_delta = -best_delta;
  
  for (divisor_idx = 0; 
  divisor_idx < (1 << ADC_CLKSEL_WIDTH); 
  divisor_idx++)
  {
    divisor = (1 << divisor_idx);
    new_freq = clk / divisor;
    
    if (new_freq >= ADC_MIN_CLK && new_freq <= ADC_MAX_CLK)
    {
      delta = freq - new_freq;
      if (delta < 0)
        delta = -delta;
      
      if (delta < best_delta)
      {
        best_delta = delta;
        best_divisor_idx = divisor_idx;
      }
    }
  }
  
  /* do logic in temp to prevent multiple writes to ADC->pcr */
  temp = (adccfgptr->regptr->adcpcr & ~ADC_CLKSEL_MASK);
  temp |= ADC_CLKSEL_SET(best_divisor_idx);
  adccfgptr->regptr->adcpcr = temp;
  
  return adc_get_clock(adccfgptr);
}

/*********************************************************************** 
* 
* Function: adc_time_2_clock
* 
* Purpose: 
*  Convert usec delay time to ADC clocks.
* 
* Processing: 
*  Compute the number of ADC clocks equivalent to the time passed.
* 
* Parameters: 
*  adccfgptr:   Pointer to ADC config structure
*  time:				time duration to be converted in to ADC clocks
* 
* Outputs:  
* 
* Returns: 
*  The number of ADC clocks equivalent to the time passed. 
* 
* Notes: None
* 
**********************************************************************/ 
static UNS_32 adc_time_2_clock(ADC_CFG_T* adccfgptr, UNS_32 time)
{
  UNS_32 adc_clcks = 0;        
  
  if(time > 0)
  {
    /* calculate the settling time clocks */
    adc_clcks = adc_get_clock(adccfgptr) / 
      (1000000 / time);
    if(adc_clcks > _BIT(ADC_SETTIME_WIDTH))
      adc_clcks = _BITMASK(ADC_SETTIME_WIDTH);
  }
  
  return adc_clcks;
}

/***********************************************************************
*
* Function: adc_default
*
* Purpose: Places the ADC interface and controller in a default state
*
* Processing:
*     Disable ADC interrupts, set ADC power control to off (idle) with
*     maximum clock divider and 1 conversion, set general configuration
*     to continuous conversion mode. Set up each MUX input to maximum
*     clock with default references. Set up idle high and low control
*     words. Clear the ADC FIFO and clear any latched interrupts.
*
* Parameters:
*     adcregs: Pointer to an ADC register set
*     xtal_in: On board clock osillator frequency. If 0 the ADC clock
*							 settings are not changed.
*     sel_SCOC: Specifies whether to use XTAL_IN as ADC clock source
*
* Outputs: 
*
* Returns: 
*  ADC clock frequency. 
*
* Notes: None
*
**********************************************************************/
static UNS_32 adc_default(ADC_REGS_T *adcregs, UNS_32 xtal_in, 
                          BOOL_32 sel_SCOC)
{
  INT_32 idx;
  UNS_32 temp;
  UNS_32 adc_clock_source;
  
  if(xtal_in)
  {
    /* setup and enable ADC clock in RCPC registers */
    RCPC->adcclkprescale = RCPC_PRESCALER_DIV1;
    if(sel_SCOC == TRUE)
    {
      RCPC->periphclksel |= RCPC_PCLKSEL1_ADC_SCOC;
      /* since we set ADC predivisor to 1 ADC clock source equal to 
      System oscilator - XTAL_IN */
      adc_clock_source = xtal_in;
    }
    else
    {  
      /* select HCLK as ADC clock source */
      RCPC->periphclksel &= ~RCPC_PCLKSEL1_ADC_SCOC;
      /* since we set ADC predivisor to 1 ADC clock source equal to 
      HCLK*/
      adc_clock_source = RCPC_GET_HCLK(xtal_in);
    }
   
    /* enable clock to ADC block */
    RCPC->periphclkctrl1 &= ~RCPC_CLKCTRL1_ADC_DISABLE;
  }
  
  
  /* enable ADC pins in IOCON registers */
  temp = IOCON->mux_ctl_25;
  temp &= (IOCON_MUX_MASK(IOCON_RES25_AN2_PJ3) & 
    IOCON_MUX_MASK(IOCON_RES25_AN3_PJ0) &
    IOCON_MUX_MASK(IOCON_RES25_AN4_PJ1) &
    IOCON_MUX_MASK(IOCON_RES25_AN5_PJ5_INT5) &
    IOCON_MUX_MASK(IOCON_RES25_AN6_PJ7_INT7) &
    IOCON_MUX_MASK(IOCON_RES25_AN7_PJ6_INT6) &
    IOCON_MUX_MASK(IOCON_RES25_AN8_PJ4) &
    IOCON_MUX_MASK(IOCON_RES25_AN9_PJ2));
  
  temp |= IOCON_MUX25_AN2_LL | IOCON_MUX25_AN3_LR |
    IOCON_MUX25_AN4_WIPER | IOCON_MUX25_AN5 |
    IOCON_MUX25_AN6 | IOCON_MUX25_AN7 | IOCON_MUX25_AN8 |
    IOCON_MUX25_AN9;
  
  IOCON->mux_ctl_25 = temp;
  
  /* Setup default state of ADC as idle, with all channels set up
  in a safe configuration, and all interrupts masked */
  /* Mask all interrupts */
  adcregs->adcie = 0;
  
  /* Setup mode as disabled, 1 conversion in a sequence, and
  maximum ADC clock divider */
  adcregs->adcpcr = (ADC_NOC_SET(1) | ADC_PWM_ALL_OFF |
    ADC_CLKSEL_DIV128);
  
    /* Set conversion mode to continuous with a single FIFO entry
  watermark level */
  adcregs->adcgencfg = (ADC_SSM_SSB | ADC_WM_SET(1));
  
  /* Set up each control bank register to use a linear analog
  input mapped array with maximum settling time */
  for (idx = 0; idx <= 15; idx++)
  {
    /* High control word */
    adcregs->adchicl[idx] = (ADC_SETTIME(0x1FF) |
      ADC_INPSEL(idx) | ADC_INM_GND | ADC_REF_VREFP);
    
    /* Low control word */
    adcregs->adclocl[idx] = ADC_REF_VREFN;
  }
  
  /* Setup idle mode high and low words using analog input 0
  as the default idle input */
  adcregs->adcidlehi = (ADC_SETTIME(0x1FF) | ADC_INP_AN0 |
    ADC_INM_GND | ADC_REF_VREFP);
  adcregs->adcidlelo = ADC_REF_VREFP;
  
  /* Make sure the FIFO is clear */
  while ((adcregs->adcfifosts & ADC_FIFO_EMPTY) == 0)
  {
    idx = (INT_32) adcregs->adcresults;
  }
  
  /* Clear pending ADC interrupts */
  adcregs->adcic = (ADC_EOS_CLR | ADC_PEN_CLR | ADC_BROWNOUT_CLR);
  
  return adc_clock_source;
}

/***********************************************************************
*
* Function: adc_add_sequence_entry
*
* Purpose: Adds a new sample entry to the sequence list
*
* Processing:
*     If the number of existing conversion sequence entries is greater
*     than 16, then return _ERROR to the caller. Otherwise, generate
*     the high and low sequence control words and place them into the
*     the sequence register array indexed by conv_count. Set status to
*     conv_count and increment conv_count by one. Return conv_count to
*     the caller.
*
* Parameters:
*     adc_ch_cfgptr: Pointer to a channel configuration structure
*     adccfgptr:     Pointer to ADC config structure
*
* Outputs: None
*
* Returns: A key to the new sequence entry (0 to 15)
*
* Notes: None
*
**********************************************************************/
static STATUS adc_add_sequence_entry(ADC_CH_CONV_T *adc_ch_cfgptr,
                                     ADC_CFG_T *adccfgptr)
{
  UNS_32 tmphi, tmplo;
  STATUS status = _ERROR;
  
  /* Limit conversion count to 16 conversions */
  if (adccfgptr->conv_count < 16)
  {
  /* Build the high and low control words based on the passed
    channel configuration values */
    tmphi = (ADC_SETTIME(adc_time_2_clock(adccfgptr, adc_ch_cfgptr->settle_time))
      | ADC_INPSEL(adc_ch_cfgptr->inpc) 
      | ADC_INNSEL(adc_ch_cfgptr->innc) 
      | ADC_REFP_SEL(adc_ch_cfgptr->vrefp));
    
    /* Build and save the control bank low word register */
    tmplo = (ADC_REFN_SEL(adc_ch_cfgptr->vrefn) |

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -