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

📄 wmauxadc.c

📁 WM9713 audio codec driver for WinCE 5.0
💻 C
📖 第 1 页 / 共 3 页
字号:
/*-----------------------------------------------------------------------------
 * Copyright (c) Wolfson Microelectronics plc.  All rights reserved.
 *
 * This software as well as any related documentation is furnished under 
 * license and may only be used or copied in accordance with the terms of the 
 * license. The information in this file is furnished for informational use 
 * only, is subject to change without notice, and should not be construed as 
 * a commitment by Wolfson Microelectronics plc. Wolfson Microelectronics plc
 * assumes no responsibility or liability for any errors or inaccuracies that
 * may appear in this document or any software that may be provided in
 * association with this document. 
 *
 * Except as permitted by such license, no part of this document may be 
 * reproduced, stored in a retrieval system, or transmitted in any form or by 
 * any means without the express written consent of Wolfson Microelectronics plc. 
 *
 * $Id: WMAuxADC.c 2326 2005-10-20 08:40:38Z ib $
 *
 * This file contains platform-independent routines for controlling
 * the analogue to digital converters on Wolfson codecs.
 *
 * Warning:
 *  This driver is specifically written for Wolfson Codecs. It is not a 
 *  general CODEC device driver.
 *
 * -----------------------------------------------------------------------------*/

/*
 * IMPORTANT
 *
 * The functions in this file must obey two rules:
 *
 * 1. They do not use any memory other than stack space and parameters passed in.
 * 2. They do not make system calls, unless WMSystemCallsAllowed returns TRUE.
 *
 * All functions take a context parameter, which passes in pointers to the virtual
 * addresses of memory-mapped registers, and stores what type of device is being
 * accessed.
 * 
 * Some client functions provide shared memory via the v_pWMData member of the
 * context structure.  This cannot be relied on.  However, the v_pADCData member
 * can be relied on by functions in this file.
 */
 
/*
 * Include files
 */
#include "WMCommon.h"
#include "WMGlobals.h"
#include "WMControlLink.h"
#include "WMPlatformACLink.h"
#include "WMDevice.h"
#include "WMTouch.h"
#include "WMAuxADC.h"
#include "WMTouchDefs.h"
#include "WMPower.h"

#if WM_AUXADC
/*
 * Global definitions
 */

/* Mapping from ADC reading to bucket */
#define BUCKET_INDEX_FROM_ADCADR( _adcAdr )   (((_adcAdr) & WM_AUXADC_MASK) >> 12)
#define ADCADR_FROM_BUCKET_INDEX( _bucket )   (((_bucket) << 12) & WM_AUXADC_MASK)

/* Mapping from ADCVAL to details */
#define INDEX_FROM_ADCVAL( _adcVal )    ((_adcVal & 0x0FFF) - 1)

/* The active mask for the touch buckets */
#define XCOORD_BUCKET   BUCKET_INDEX_FROM_ADCADR(WM_AUXADC_X_COORD)
#define YCOORD_BUCKET   BUCKET_INDEX_FROM_ADCADR(WM_AUXADC_Y_COORD)
#define TOUCH_ACTIVE_MASK   ((1 << XCOORD_BUCKET) | (1 << YCOORD_BUCKET))

/* Convert between ADCSEL, bucket and ADCADR */
#define BIT_MASK( _bucket )                     (1U << (_bucket))
#define ADCSEL_FROM_BUCKET_MASK( _bucketMask )  ((_bucketMask) & WM_ADCSEL_MASK)
#define BUCKET_MASK_FROM_ADCSEL( _adcsel )      ((_adcsel))
#define ADCSEL_FROM_BUCKET_INDEX( _bucket )     ADCSEL_FROM_BUCKET_MASK( BIT_MASK( _bucket ) )
#define ADCSEL_FROM_ADCADR( _adcAdr )           ADCSEL_FROM_BUCKET_INDEX( BUCKET_INDEX_FROM_ADCADR(_adrAdr) )

/*
 * The maximum number of attempts before we decide we're not getting data.
 */
#define SAMPLE_CYCLE_COUNT      10

/*
 * The length of time (in microseconds) to wait between attempts if there's nothing
 * in the FIFO.  Note frame rate is 48 kHZ - i.e. ~20.83us per frame.
 */
#define SAMPLE_DATA_WAIT        50

/*
 * The duration of a frame.
 */
#define FRAME_TIME              21

/*
 * Private data
 */

/*
 * Function prototypes
 */
static WMSTATUS private_PollADC( WM_DEVICE_HANDLE hDevice,
                                 WM_REGVAL adc,
                                 WM_REGVAL *pValue
                                 );

#if WM_STREAM_AUXADC
static WMSTATUS private_SwitchStreaming( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_SampleADC( WM_DEVICE_HANDLE hDevice,
                                   WM_REGVAL adc,
                                   WM_REGVAL *pValue
                                   );
static WM_REGVAL private_GetAdcSelVal( WM_DEVICE_HANDLE hDevice );
static WMSTATUS private_GetADCValue( WM_DEVICE_HANDLE hDevice );
static void private_PrepareBucket( WM_DEVICE_HANDLE hDevice, WM_REGVAL adcAdr );
#endif /* WM_STREAM_AUXADC */

/*-----------------------------------------------------------------------------
 * Function:    WMAuxADCInit
 *
 * Initialises the ADC functionality.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *
 * Returns:     WMSTATUS
 *		See WMStatus.h
 *---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCInit( WM_DEVICE_HANDLE hDevice )
{
#if WM_STREAM_AUXADC || defined(DEBUG)
    WM_DEVICE_CONTEXT   *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
#endif /* WM_STREAM_AUXADC || DEBUG */
    WMSTATUS            status;

    /*
     * Take the mutex.
     */
    if ( !WMLockGlobalData( hDevice ) )
    {
        status = WMS_LOCK_TIMED_OUT;
        goto error0;
    }

    /* Check it's a device with touch panel */
    if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
    {
        WM_TRACE( hDevice, 
                 ("WMAuxADCInit: There is no Auxiliary "
                  "ADC Support for this Wolfson Device! 0x%X",
                  pDeviceContext->deviceType
                ));
        status = WMS_UNSUPPORTED;
        goto error1;
    }

#if WM_STREAM_AUXADC
    if ( !(pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_INITIALISED) )
    {
        int         adc;

        /*
         * We don't have an ADC selected.
         */
        pDeviceContext->v_pADCData->activeADCs = 0;
        pDeviceContext->v_pADCData->flags &= ~WM_DRVCTX_AUXADC_TOUCH_STREAMING;

        /*
         * Now make sure all readings are marked invalid.
         */
        for ( adc = 0; adc < ADC_COUNT; adc++ )
        {
            pDeviceContext->v_pADCData->reading[adc] = WM_INVALID_SAMPLE;
            pDeviceContext->v_pADCData->lastReading[adc] = WM_INVALID_SAMPLE;
        }

        /* We're initialised now */
        pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_INITIALISED;
    }
#endif /* WM_STREAM_AUXADC */

    /*
     * Let other threads in.
     */
    WMUnlockGlobalData( hDevice );

    return WMS_SUCCESS;

error1:
    WMUnlockGlobalData( hDevice );

error0:
    return status;
}

/*-----------------------------------------------------------------------------
 * Function:    WMAuxADCShutdown
 *
 * Shuts down the ADC functionality.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *
 * Returns:     void
 *---------------------------------------------------------------------------*/
void WMAuxADCShutdown( WM_DEVICE_HANDLE hDevice )
{
    /* Power down the auxiliary ADC functions. */
    WMAuxADCPowerDown( hDevice, WM_POWER_AUXADC );

    /* And shut down the Control Link. */
    WMLinkShutdown( hDevice, WM_DRIVER_AUXADC );
}

/*-----------------------------------------------------------------------------
 * Function:    WMAuxADCStart
 *
 * Prepares the ADC functionality to generate readings of the appropriate type.
 *
 * Note the ADCs are mutually exclusive - selecting one deselects the previous
 * one.  The exceptions to this are the X- and Y-coordinates, which can be
 * streamed along with the ADC reading.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *      adc                 Which ADC to read from.
 *
 * Returns:     WMSTATUS
 *		See WMStatus.h
 *---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCStart( WM_DEVICE_HANDLE hDevice, WM_AUXADC_TYPE adc )
{
    WMSTATUS            status;

    /* Check we've got AUX ADC */
    if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
    {
        status = WMS_UNSUPPORTED;
        goto error0;
    }

#if WM_STREAM_AUXADC
    {
        WM_DEVICE_CONTEXT   *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
        unsigned int        index;
        unsigned int        bucket;
        WM_REGVAL           adcAdr;
    
        /*
         * We only have to do anything in streaming mode.
         */
    
        /*
         * Protect ourselves from interference.
         */
        if ( !WMLockGlobalData( hDevice ) )
        {
            status = WMS_LOCK_TIMED_OUT;
            goto error0;
        }
    
        /*
         * Touch is a special case.
         * Note WM_ADC_TOUCH is 0x0003, which is conveniently 
         * WM_ADC_X_COORD|WM_ADC_Y_COORD (0x0001|0x0002).
         */
        if ( ( adc & WM_ADC_TOUCH ) == adc )
        {
            if ( pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_TOUCH_STREAMING )
            {
                /* Nothing to do */
                goto done;
            }
            pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_TOUCH_STREAMING;
    
            /* Prepare the buckets */
            bucket = BUCKET_INDEX_FROM_ADCADR( WM_AUXADC_X_COORD );
            WM_ASSERT( hDevice, bucket < ADC_COUNT );
            WM_ASSERT( hDevice, XCOORD_BUCKET == bucket );
            pDeviceContext->v_pADCData->reading[bucket] = WM_INVALID_SAMPLE;
            pDeviceContext->v_pADCData->lastReading[bucket] = WM_INVALID_SAMPLE;
            pDeviceContext->v_pADCData->activeADCs |= 1 << bucket;
    
            bucket = BUCKET_INDEX_FROM_ADCADR( WM_AUXADC_Y_COORD );
            WM_ASSERT( hDevice, bucket < ADC_COUNT );
            pDeviceContext->v_pADCData->reading[bucket] = WM_INVALID_SAMPLE;
            pDeviceContext->v_pADCData->lastReading[bucket] = WM_INVALID_SAMPLE;
            pDeviceContext->v_pADCData->activeADCs |= 1 << bucket;
        }
        else
        {
            /* Work out the index into our table */
            index = INDEX_FROM_ADCVAL( adc );
            WM_ASSERT( hDevice, index < pDeviceContext->pChipDef->adcCount );
    
            /* Now look up the address */
            adcAdr = pDeviceContext->pChipDef->pAuxADCDetails[index].adcAdr;
            bucket = BUCKET_INDEX_FROM_ADCADR( adcAdr );
            WM_ASSERT( hDevice, bucket < ADC_COUNT );
    
            if ( pDeviceContext->v_pADCData->activeADCs & (1 << bucket) )
            {
                /* Nothing to do */
                goto done;
            }
    
            pDeviceContext->v_pADCData->flags |= WM_DRVCTX_AUXADC_ADC_STREAMING;
    
            /* Now prepare the bucket */
            private_PrepareBucket( hDevice, adcAdr );
        }
    
        /*
         * If we get here, we've got a change.
         */
        status = private_SwitchStreaming( hDevice );
        if ( WM_ERROR( status ) )
    	{
    		goto error1;
    	}
    
    done:
        /*
         * Let other threads in.
         */
        WMUnlockGlobalData( hDevice );
    }
#endif  /* WM_STREAM_AUXADC */

    return WMS_SUCCESS;

#if WM_STREAM_AUXADC
error1:
    /*
     * Let other threads in.
     */
    WMUnlockGlobalData( hDevice );
#endif /* WM_STREAM_AUXADC */
error0:
    return status;
}

/*-----------------------------------------------------------------------------
 * Function:    WMAuxADCSelect
 *
 * Prepares the ADC functionality to generate readings of the appropriate type,
 * but doesn't start streaming.
 *
 * Note the ADCs are mutually exclusive - selecting one deselects the previous
 * one.  The exceptions to this are the X- and Y-coordinates, which can be
 * streamed along with the ADC reading.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *      adc                 Which ADC to read from.
 *
 * Returns:     WMSTATUS
 *		See WMStatus.h
 *---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCSelect( WM_DEVICE_HANDLE hDevice, WM_AUXADC_TYPE adc )
{
    WMSTATUS            status = WMS_SUCCESS;

    /* Check we've got AUX ADC */
    if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
    {
        status = WMS_UNSUPPORTED;
        goto error0;
    }

#if WM_STREAM_AUXADC
    {
        WM_DEVICE_CONTEXT   *pDeviceContext = WMHANDLE_TO_DEVICE( hDevice );
        unsigned int        index;
        WM_REGVAL           adcAdr;
        WM_BOOL             adcStreaming = FALSE;
    
        /*
         * We only have to do anything in streaming mode.
         */
    
        /*
         * Protect ourselves from interference.
         */
        if ( !WMLockGlobalData( hDevice ) )
        {
            status = WMS_LOCK_TIMED_OUT;
            goto error0;
        }
    
        /*
         * Touch is a special case, and should always use WMAuxADCStart.
         * Note WM_ADC_TOUCH is 0x0003, which is conveniently 
         * WM_ADC_X_COORD|WM_ADC_Y_COORD (0x0001|0x0002).
         */
        WM_ASSERT( hDevice, ( adc & WM_ADC_TOUCH ) != adc );
    
        /* Remember whether the ADC has asked to stream. */
        adcStreaming = pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_ADC_STREAMING;
    
        /*
         * If we're streaming, switch ADCs.
         */
        if ( pDeviceContext->v_pADCData->flags & WM_DRVCTX_AUXADC_STREAMING )
        {
            status = WMAuxADCStart( hDevice, adc );
        }
        else
        {
            /*
             * Otherwise, remember which ADC in case we do start streaming.
             */
            index = INDEX_FROM_ADCVAL( adc );
            WM_ASSERT( hDevice, index < pDeviceContext->pChipDef->adcCount );
    
            /* Now look up the address */
            adcAdr = pDeviceContext->pChipDef->pAuxADCDetails[index].adcAdr;
    
            /* And prepare the bucket */
            private_PrepareBucket( hDevice, adcAdr );
        }
    
        /*
         * If we're only streaming because of touch, keep it that way.
         */
        if ( !adcStreaming )
        {
            pDeviceContext->v_pADCData->flags &= ~WM_DRVCTX_AUXADC_ADC_STREAMING;
        }
    
        /*
         * Let other threads in.
         */
        WMUnlockGlobalData( hDevice );
    }
#endif  /* WM_STREAM_AUXADC */

    return status;

error0:
    return status;
}

/*-----------------------------------------------------------------------------
 * Function:    WMAuxADCStop
 *
 * Stops the ADC functionality from generating readings of the appropriate type.
 *
 * Parameters:
 *      hDevice             handle to the device (from WMOpenDevice)
 *      adc                 Which ADC to stop.
 *
 * Returns:     WMSTATUS
 *		See WMStatus.h
 *---------------------------------------------------------------------------*/
WMSTATUS WMAuxADCStop( WM_DEVICE_HANDLE hDevice, WM_AUXADC_TYPE adc )
{
    WMSTATUS            status;

    /* Check we've got AUX ADC */
    if ( !WM_IS_AUXADC_SUPPORTED( hDevice ) )
    {

⌨️ 快捷键说明

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