//***************************************************************************** // //! @file am_hal_adc.c //! //! @brief Functions for Interfacing with the Analog to Digital Converter. //! //! @addtogroup adc3p ADC - Analog-to-Digital Converter //! @ingroup apollo3p_hal //! @{ // //***************************************************************************** //***************************************************************************** // // Copyright (c) 2024, Ambiq Micro, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package. // //***************************************************************************** #include #include #include "am_mcu_apollo.h" //***************************************************************************** // //! Private Types. // //***************************************************************************** #define AM_HAL_MAGIC_ADC 0xAFAFAF #define AM_HAL_ADC_CHK_HANDLE(h) ((h) && ((am_hal_handle_prefix_t *)(h))->s.bInit && (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_ADC)) // **************************************************************************** // //! Apollo3 Temperature Trim Value Locations and default coefficients. // // **************************************************************************** #define AM_HAL_ADC_CALIB_TEMP_ADDR (0x50023840) #define AM_HAL_ADC_CALIB_AMBIENT_ADDR (0x50023844) #define AM_HAL_ADC_CALIB_ADC_OFFSET_ADDR (0x50023848) // **************************************************************************** // //! Default coefficients (used when trims not provided): //! TEMP_DEFAULT = Temperature in deg K (e.g. 299.5 - 273.15 = 26.35) //! AMBIENT_DEFAULT = Voltage measurement at default temperature. //! OFFSET_DEFAULT = Default ADC offset at 1v. // // **************************************************************************** #define AM_HAL_ADC_CALIB_TEMP_DEFAULT (299.5F) #define AM_HAL_ADC_CALIB_AMBIENT_DEFAULT (1.02809F) #define AM_HAL_ADC_CALIB_ADC_OFFSET_DEFAULT (-0.004281F) // //! ADC Power save register state. // typedef struct { bool bValid; uint32_t regCFG; uint32_t regSL0CFG; uint32_t regSL1CFG; uint32_t regSL2CFG; uint32_t regSL3CFG; uint32_t regSL4CFG; uint32_t regSL5CFG; uint32_t regSL6CFG; uint32_t regSL7CFG; uint32_t regWULIM; uint32_t regWLLIM; uint32_t regINTEN; } am_hal_adc_register_state_t; // //! ADC State structure. // typedef struct { // //! Handle validation prefix. // am_hal_handle_prefix_t prefix; // //! Physical module number. // uint32_t ui32Module; // //! ADC Capabilities. // am_hal_adc_capabilities_t capabilities; //! Power Save-Restore register state am_hal_adc_register_state_t registerState; } am_hal_adc_state_t; //***************************************************************************** // //! @brief Private SRAM view of temperature trims. //! //! This static SRAM union is private to the ADC HAL functions. // //***************************************************************************** static union { //! These trim values are loaded as uint32_t values. struct { //! Temperature of the package test head (in degrees Kelvin) uint32_t ui32CalibrationTemperature; //! Voltage corresponding to temperature measured on test head. uint32_t ui32CalibrationVoltage; //! ADC offset voltage measured on the package test head. uint32_t ui32CalibrationOffset; //! Flag if default (guess) or measured. bool bMeasured; } ui32; //! These trim values are accessed as floats when used in temp calculations. struct { //! Temperature of the package test head in degrees Kelvin float fCalibrationTemperature; //! Voltage corresponding to temperature measured on test head. float fCalibrationVoltage; //! ADC offset voltage measured on the package test head. float fCalibrationOffset; //! Flag if default (guess) or measured. float fMeasuredFlag; } flt; } priv_temp_trims; //***************************************************************************** // //! Global Variables. // //***************************************************************************** am_hal_adc_state_t g_ADCState[AM_REG_ADC_NUM_MODULES]; uint32_t g_ADCSlotsConfigured; // //! Storage for pre-computed constant terms in the temperature sensor equation. // static float g_fTempEqnTerms = 0.0F; //***************************************************************************** // // @brief ADC initialization function // // @param ui32Module - module instance. // @param ppHandle - returns the handle for the module instance. // // This function accepts a module instance, allocates the interface and then // returns a handle to be used by the remaining interface functions. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_initialize(uint32_t ui32Module, void **ppHandle) { #ifndef AM_HAL_DISABLE_API_VALIDATION // //! Validate the module number // if ( ui32Module >= AM_REG_ADC_NUM_MODULES ) { return AM_HAL_STATUS_OUT_OF_RANGE; } // //! Check for valid arguements. // if ( !ppHandle ) { return AM_HAL_STATUS_INVALID_ARG; } // //! Check if the handle is unallocated. // if ( g_ADCState[ui32Module].prefix.s.bInit ) { return AM_HAL_STATUS_INVALID_OPERATION; } #endif // AM_HAL_DISABLE_API_VALIDATION // //! Initialize the handle. // g_ADCState[ui32Module].prefix.s.bInit = true; g_ADCState[ui32Module].prefix.s.magic = AM_HAL_MAGIC_ADC; g_ADCState[ui32Module].ui32Module = ui32Module; // //! Initialize the number of slots configured. // g_ADCSlotsConfigured = 0; // //! Return the handle. // *ppHandle = (void *)&g_ADCState[ui32Module]; // //! Before returning, grab the temperature trims. // priv_temp_trims.ui32.ui32CalibrationTemperature = am_hal_flash_load_ui32((uint32_t*)AM_HAL_ADC_CALIB_TEMP_ADDR); priv_temp_trims.ui32.ui32CalibrationVoltage = am_hal_flash_load_ui32((uint32_t*)AM_HAL_ADC_CALIB_AMBIENT_ADDR); priv_temp_trims.ui32.ui32CalibrationOffset = am_hal_flash_load_ui32((uint32_t*)AM_HAL_ADC_CALIB_ADC_OFFSET_ADDR); if ( (priv_temp_trims.ui32.ui32CalibrationTemperature == 0xffffffff) || (priv_temp_trims.ui32.ui32CalibrationVoltage == 0xffffffff) || (priv_temp_trims.ui32.ui32CalibrationOffset == 0xffffffff) ) { // //! @note Since the device has not been calibrated on the tester, we'll load //! default calibration values. These default values should result //! in worst-case temperature measurements of +-6 degress C. // priv_temp_trims.flt.fCalibrationTemperature = AM_HAL_ADC_CALIB_TEMP_DEFAULT; priv_temp_trims.flt.fCalibrationVoltage = AM_HAL_ADC_CALIB_AMBIENT_DEFAULT; priv_temp_trims.flt.fCalibrationOffset = AM_HAL_ADC_CALIB_ADC_OFFSET_DEFAULT; priv_temp_trims.ui32.bMeasured = false; } else { priv_temp_trims.ui32.bMeasured = true; } // //! Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief MSPI deinitialization function // @note This function accepts a handle to an instance and de-initializes the // interface. // // @param pHandle - returns the handle for the module instance. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_deinitialize(void *pHandle) { uint32_t status = AM_HAL_STATUS_SUCCESS; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION am_hal_adc_state_t *pADCState = (am_hal_adc_state_t *)pHandle; if ( pADCState->prefix.s.bEnable ) { status = am_hal_adc_disable(pHandle); } pADCState->prefix.s.bInit = false; // // Return the status. // return status; } //***************************************************************************** // // @brief ADC configuration function // @note This function configures the ADC for operation. // // @param pHandle - handle for the module instance. // @param psConfig - pointer to the configuration structure. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_configure(void *pHandle, am_hal_adc_config_t *psConfig) { uint32_t ui32Config; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION am_hal_adc_state_t *pADCState = (am_hal_adc_state_t *)pHandle; uint32_t ui32Module = pADCState->ui32Module; ui32Config = 0; // // Set the ADC clock source. // ui32Config |= _VAL2FLD(ADC_CFG_CLKSEL, psConfig->eClock); // // Set the ADC trigger polarity. // ui32Config |= _VAL2FLD(ADC_CFG_TRIGPOL, psConfig->ePolarity); // // Set the ADC trigger. // ui32Config |= _VAL2FLD(ADC_CFG_TRIGSEL, psConfig->eTrigger); // // Set the ADC reference voltage. // ui32Config |= _VAL2FLD(ADC_CFG_REFSEL, psConfig->eReference); // // Set the Destructive FIFO read. // ui32Config |= _VAL2FLD(ADC_CFG_DFIFORDEN, 1); // // Set the ADC clock mode. // ui32Config |= _VAL2FLD(ADC_CFG_CKMODE, psConfig->eClockMode); // // Set the ADC low power mode. // ui32Config |= _VAL2FLD(ADC_CFG_LPMODE, psConfig->ePowerMode); // // Set the ADC repetition mode. // ui32Config |= _VAL2FLD(ADC_CFG_RPTEN, psConfig->eRepeat); // // Set the configuration in the ADC peripheral. // ADCn(ui32Module)->CFG = ui32Config; // // Return status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC slot configuration function // @note This function configures the ADC slot for operation. // // @param pHandle - handle for the module instance. // @param ui32SlotNumber - slot number // @param pSlotConfig - pointer to the configuration structure. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_configure_slot(void *pHandle, uint32_t ui32SlotNumber, am_hal_adc_slot_config_t *pSlotConfig) { uint32_t ui32Config; uint32_t ui32RegOffset; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION am_hal_adc_state_t *pADCState = (am_hal_adc_state_t *)pHandle; uint32_t ui32Module = pADCState->ui32Module; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the slot number. // if ( ui32SlotNumber >= AM_HAL_ADC_MAX_SLOTS ) { return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION ui32Config = 0; // // Set the measurements to average // ui32Config |= _VAL2FLD(ADC_SL0CFG_ADSEL0, pSlotConfig->eMeasToAvg); // // Set the precision mode. // ui32Config |= _VAL2FLD(ADC_SL0CFG_PRMODE0, pSlotConfig->ePrecisionMode); // // Set the channel. // ui32Config |= _VAL2FLD(ADC_SL0CFG_CHSEL0, pSlotConfig->eChannel); // // Enable window comparison if configured. // ui32Config |= _VAL2FLD(ADC_SL0CFG_WCEN0, pSlotConfig->bWindowCompare); // // Enable the slot if configured. // ui32Config |= _VAL2FLD(ADC_SL0CFG_SLEN0, pSlotConfig->bEnabled); // // Locate the correct register for this ADC slot. // ui32RegOffset = ((uint32_t)&ADCn(ui32Module)->SL0CFG) + (4 * ui32SlotNumber); // // Write the register with the caller's configuration value. // AM_REGVAL(ui32RegOffset) = ui32Config; // // Update the nubmer of slots configured. // g_ADCSlotsConfigured++; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC DMA configuration function // // @param pHandle - handle for the module instance. // @param pDMAConfig - pointer to the configuration structure. // // This function configures the ADC DMA for operation. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_configure_dma(void *pHandle, am_hal_adc_dma_config_t *pDMAConfig) { uint32_t ui32Config; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t *)pHandle)->ui32Module; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check for DMA to/from DTCM. // if ( (pDMAConfig->ui32TargetAddress >= AM_HAL_FLASH_DTCM_START) && (pDMAConfig->ui32TargetAddress <= AM_HAL_FLASH_DTCM_END) ) { return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION ui32Config = 0; // // Configure the DMA complete power-off. // ui32Config |= _VAL2FLD(ADC_DMACFG_DPWROFF, 0); // DPWROFF not supported! // // Configure the data to be transferred. // if ( g_ADCSlotsConfigured > 1 ) { // Need slot number to distinguish between slot results. ui32Config |= _VAL2FLD(ADC_DMACFG_DMAMSK, ADC_DMACFG_DMAMSK_DIS); } else { ui32Config |= _VAL2FLD(ADC_DMACFG_DMAMSK, ADC_DMACFG_DMAMSK_EN); } // // Enable DMA Halt on Status (DMAERR or DMACPL) by default. // ui32Config |= _VAL2FLD(ADC_DMACFG_DMAHONSTAT, ADC_DMACFG_DMAHONSTAT_EN); // // Configure the DMA dynamic priority handling. // ui32Config |= _VAL2FLD(ADC_DMACFG_DMADYNPRI, pDMAConfig->bDynamicPriority); // // Configure the DMA static priority. // ui32Config |= _VAL2FLD(ADC_DMACFG_DMAPRI, pDMAConfig->ePriority); // // Enable the DMA (does not start until ADC is enabled and triggered). // ui32Config |= _VAL2FLD(ADC_DMACFG_DMAEN, ADC_DMACFG_DMAEN_EN); // // Set the DMA configuration. // ADCn(ui32Module)->DMACFG = ui32Config; // // Set the DMA transfer count. // ADCn(ui32Module)->DMATOTCOUNT_b.TOTCOUNT = pDMAConfig->ui32SampleCount; // // Set the DMA target address. // ADCn(ui32Module)->DMATARGADDR = pDMAConfig->ui32TargetAddress; // // Set the DMA trigger on FIFO 75% full. // ADCn(ui32Module)->DMATRIGEN = ADC_DMATRIGEN_DFIFO75_Msk; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC device specific control function. // // @param pHandle - handle for the module instance. // @param eRequest - enum request type // @param pArgs - pointer to pArgs (array of three floats) // // This function provides for special control functions for the ADC operation. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_control(void *pHandle, am_hal_adc_request_e eRequest, void *pArgs) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t *)pHandle)->ui32Module; switch ( eRequest ) { case AM_HAL_ADC_REQ_WINDOW_CONFIG: { am_hal_adc_window_config_t *pWindowConfig = (am_hal_adc_window_config_t *)pArgs; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the window limits. // if ( (pWindowConfig->ui32Upper > ADC_WULIM_ULIM_Msk) || (pWindowConfig->ui32Lower > ADC_WLLIM_LLIM_Msk) ) { return AM_HAL_STATUS_OUT_OF_RANGE; } #endif // AM_HAL_DISABLE_API_VALIDATION // // Set the window comparison upper and lower limits. // ADCn(ui32Module)->WULIM = _VAL2FLD(ADC_WULIM_ULIM, pWindowConfig->ui32Upper); ADCn(ui32Module)->WLLIM = _VAL2FLD(ADC_WLLIM_LLIM, pWindowConfig->ui32Lower); // // Set the window scale per precision mode if indicated. // ADCn(ui32Module)->SCWLIM = _VAL2FLD(ADC_SCWLIM_SCWLIMEN, pWindowConfig->bScaleLimits); } break; case AM_HAL_ADC_REQ_TEMP_CELSIUS_GET: // // pArgs must point to an array of 3 floats. To assure that the // array is valid, upon calling the 3rd float (pArgs[2]) must be // set to the value -123.456F. // if ( pArgs != NULL ) { float *pfArray = (float*)pArgs; float fTemp, fCalibration_temp, fCalibration_voltage, fCalibration_offset, fVoltage; if ( pfArray[2] == -123.456F ) { // // The caller has provided a voltage as determined from the // sample. The sample is scaled up by the reference voltage // used on the device and then scaled down by the number of // sample bits. // i.e. scaled by AM_HAL_ADC_VREF / (1 << number_bits). // // Get the scaled voltage obtained from the ADC sample. // fVoltage = pfArray[0]; // // Compute the calibrated temperature via the equation: // T = m * Vmeas + T1 - m(V1 + Voff) // m = AM_HAL_ADC_TEMPSENSOR_SLOPE (degK / V) // Vmeas = The measured voltage (as based on the ADC code) // T1 = Calibration temperature // V1 = Calibration voltage (stored in volts) // Voff = Calibration offset (stored in volts) // fCalibration_temp = priv_temp_trims.flt.fCalibrationTemperature; fCalibration_voltage = priv_temp_trims.flt.fCalibrationVoltage; fCalibration_offset = priv_temp_trims.flt.fCalibrationOffset; // // Compute the temperature in K // if ( g_fTempEqnTerms == 0.0F ) { // // The 2nd and 3rd terms of the temperature equation are // consistent for a given device, so compute them only // the first time and save. // g_fTempEqnTerms = -1.0F * AM_HAL_ADC_TEMPSENSOR_SLOPE; g_fTempEqnTerms *= (fCalibration_voltage + fCalibration_offset); g_fTempEqnTerms += fCalibration_temp; } // // Determine the temperature in K by factoring // in the supplied sample voltage // fTemp = AM_HAL_ADC_TEMPSENSOR_SLOPE * fVoltage; fTemp += g_fTempEqnTerms; // // Give it back to the caller in Celsius. // pfArray[1] = fTemp - 273.15f; } else { return AM_HAL_STATUS_INVALID_OPERATION; } } else { return AM_HAL_STATUS_INVALID_ARG; } break; case AM_HAL_ADC_REQ_TEMP_TRIMS_GET: // // pArgs must point to an array of 4 floats. To assure that the // array is valid, upon calling the 4th float (pArgs[3]) must be // set to the value -123.456. // On return, pArgs[3] is set to 1 if the returned values are // calibrated, or 0 if default calibration values. // if ( pArgs != NULL ) { float *pfArray = (float*)pArgs; if ( pfArray[3] == -123.456F ) { // // Return trim temperature as a float. // pfArray[0] = priv_temp_trims.flt.fCalibrationTemperature; // // Return trim voltage as a float. // pfArray[1] = priv_temp_trims.flt.fCalibrationVoltage; // // Return trim ADC offset voltage (in volts) as a float. // pfArray[2] = priv_temp_trims.flt.fCalibrationOffset; // // Set the calibrated or uncalibrated flag // *(uint32_t*)&pfArray[3] = priv_temp_trims.ui32.bMeasured; } else { return AM_HAL_STATUS_INVALID_OPERATION; } } else { return AM_HAL_STATUS_INVALID_ARG; } break; default: return AM_HAL_STATUS_INVALID_ARG; } // // Return status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC enable function // // @param pHandle - handle for the module instance. // // This function enables the ADC operation. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_enable(void *pHandle) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif am_hal_adc_state_t *pADCState = (am_hal_adc_state_t *)pHandle; uint32_t ui32Module = pADCState->ui32Module; if ( pADCState->prefix.s.bEnable ) { return AM_HAL_STATUS_SUCCESS; } // // Enable the ADC. // ADCn(ui32Module)->CFG_b.ADCEN = 0x1; // // Set flag to indicate module is enabled. // pADCState->prefix.s.bEnable = true; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC disable function // // @param pHandle - handle for the module instance. // // This function disables the ADC operation. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_disable(void *pHandle) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION am_hal_adc_state_t *pADCState = (am_hal_adc_state_t *)pHandle; uint32_t ui32Module = pADCState->ui32Module; // // disable dma in progress and clear status // ADCn(ui32Module)->DMACFG_b.DMAEN = 0; ADCn(ui32Module)->DMASTAT = 0 ; // // Disable the ADC. // ADCn(ui32Module)->CFG_b.ADCEN = 0x0; // // Set flag to indicate module is disabled. // pADCState->prefix.s.bEnable = false; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC status function // // @param pHandle - handle for the interface. // @param pStatus - returns status here // // This function returns the current status of the DMA operation. // // @return status - DMA status flags. // //***************************************************************************** uint32_t am_hal_adc_status_get(void *pHandle, am_hal_adc_status_t *pStatus ) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t *)pHandle)->ui32Module; // // Get the power status. // pStatus->bPoweredOn = (ADCn(ui32Module)->STAT & ADC_STAT_PWDSTAT_Msk) == _VAL2FLD(ADC_STAT_PWDSTAT, ADC_STAT_PWDSTAT_ON); // // Get the low power mode 1 status. // pStatus->bLPMode1 = (ADCn(ui32Module)->STAT & ADC_STAT_PWDSTAT_Msk) == _VAL2FLD(ADC_STAT_PWDSTAT, ADC_STAT_PWDSTAT_POWERED_DOWN); // // Get the DMA status. // pStatus->bErr = ((ADCn(ui32Module)->DMASTAT & ADC_DMASTAT_DMAERR_Msk) > 0); pStatus->bCmp = ((ADCn(ui32Module)->DMASTAT & ADC_DMASTAT_DMACPL_Msk) > 0); pStatus->bTIP = ((ADCn(ui32Module)->DMASTAT & ADC_DMASTAT_DMATIP_Msk) > 0); // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC enable interrupts function // // @param pHandle - handle for the interface. // @param ui32IntMask - ADC interrupt mask. // // This function enables the specific indicated interrupts. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_interrupt_enable(void *pHandle, uint32_t ui32IntMask) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t*)pHandle)->ui32Module; // // Enable the interrupts. // ADCn(ui32Module)->INTEN |= ui32IntMask; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC disable interrupts function // // @param pHandle - handle for the interface. // @param ui32IntMask - ADC interrupt mask. // // This function disable the specific indicated interrupts. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_interrupt_disable(void *pHandle, uint32_t ui32IntMask) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t*)pHandle)->ui32Module; // // Disable the interrupts. // ADCn(ui32Module)->INTEN &= ~ui32IntMask; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC interrupt status function // // @param pHandle - handle for the interface. // @param pui32Status - returns interrupts enabled here // @param bEnabledOnly - if true, only return enabled interrupts // // This function returns the specific indicated interrupt status. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_interrupt_status(void *pHandle, uint32_t *pui32Status, bool bEnabledOnly) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t*)pHandle)->ui32Module; // // if requested, only return the interrupts that are enabled. // if ( bEnabledOnly ) { uint32_t ui32RetVal = ADCn(ui32Module)->INTSTAT; *pui32Status = ADCn(ui32Module)->INTEN & ui32RetVal; } else { *pui32Status = ADCn(ui32Module)->INTSTAT; } // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC interrupt clear // // @param pHandle - handle for the interface. // @param ui32IntMask - uint32_t for interrupts to clear // // This function clears the interrupts for the given peripheral. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_interrupt_clear(void *pHandle, uint32_t ui32IntMask) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t*)pHandle)->ui32Module; // // Clear the interrupts. // ADCn(ui32Module)->INTCLR = ui32IntMask; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC sample read function // // @param pHandle - handle for the module instance. // @param bFullSample - true to get a full sample including // the fractional part. // @param pui32InSampleBuffer - Ptr to the input sample buffer. // If NULL then samples will be read directly // from the FIFO. // @param pui32InOutNumberSamples - Ptr to variable containing the number of // samples. // @param pui32OutBuffer - Ptr to the required output sample buffer. // // This function reads samples from the ADC FIFO or an SRAM sample buffer // returned by a DMA operation. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_samples_read(void *pHandle, bool bFullSample, uint32_t *pui32InSampleBuffer, uint32_t *pui32InOutNumberSamples, am_hal_adc_sample_t *pui32OutBuffer) { uint32_t ui32Sample; #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } // // Check the output sample buffer pointer. // if ( NULL == pui32OutBuffer ) { return AM_HAL_STATUS_INVALID_ARG; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32RequestedSamples = *pui32InOutNumberSamples; uint32_t ui32Module = ((am_hal_adc_state_t*)pHandle)->ui32Module; *pui32InOutNumberSamples = 0; // // Check if we are reading directly from FIFO or DMA SRAM buffer. // if ( NULL == pui32InSampleBuffer ) { // // Grab a value from the ADC FIFO // do { ui32Sample = ADCn(ui32Module)->FIFOPR; pui32OutBuffer->ui32Slot = AM_HAL_ADC_FIFO_SLOT(ui32Sample); pui32OutBuffer->ui32Sample = bFullSample ? AM_HAL_ADC_FIFO_FULL_SAMPLE(ui32Sample) : AM_HAL_ADC_FIFO_SAMPLE(ui32Sample); pui32OutBuffer++; (*pui32InOutNumberSamples)++; } while ((AM_HAL_ADC_FIFO_COUNT(ui32Sample) > 0) && (*pui32InOutNumberSamples < ui32RequestedSamples)); } else { // // Process the samples from the provided sample buffer // do { pui32OutBuffer->ui32Slot = AM_HAL_ADC_FIFO_SLOT(*pui32InSampleBuffer); pui32OutBuffer->ui32Sample = AM_HAL_ADC_FIFO_SAMPLE(*pui32InSampleBuffer); pui32InSampleBuffer++; pui32OutBuffer++; (*pui32InOutNumberSamples)++; } while (*pui32InOutNumberSamples < ui32RequestedSamples); } // // Return FIFO valid bits. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief Issue Software Trigger to the ADC. // // @param pHandle - handle for the module instance. // // This function triggers the ADC operation. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_sw_trigger(void *pHandle) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION uint32_t ui32Module = ((am_hal_adc_state_t*)pHandle)->ui32Module; // // Write to the Software trigger register in the ADC. // ADCn(ui32Module)->SWT = 0x37; // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // @brief ADC power control function // // @param pHandle - handle for the interface. // @param ePowerState - the desired power state to move the peripheral to. // @param bRetainState - flag (if true) to save/restore peripheral state upon // power state change. // // This function updates the peripheral to a given power state. // // @return status - generic or interface specific status. // //***************************************************************************** uint32_t am_hal_adc_power_control(void *pHandle, am_hal_sysctrl_power_state_e ePowerState, bool bRetainState) { #ifndef AM_HAL_DISABLE_API_VALIDATION // // Check the handle. // if ( !AM_HAL_ADC_CHK_HANDLE(pHandle) ) { return AM_HAL_STATUS_INVALID_HANDLE; } #endif // AM_HAL_DISABLE_API_VALIDATION am_hal_adc_state_t *pADCState = (am_hal_adc_state_t *)pHandle; uint32_t ui32Module = pADCState->ui32Module; // // Decode the requested power state and update MSPI operation accordingly. // switch (ePowerState) { case AM_HAL_SYSCTRL_WAKE: if ( bRetainState && !pADCState->registerState.bValid ) { return AM_HAL_STATUS_INVALID_OPERATION; } // // Enable the ADC power domain. // am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PERIPH_ADC); if ( bRetainState ) { ADCn(ui32Module)->SL0CFG = pADCState->registerState.regSL0CFG; ADCn(ui32Module)->SL1CFG = pADCState->registerState.regSL1CFG; ADCn(ui32Module)->SL2CFG = pADCState->registerState.regSL2CFG; ADCn(ui32Module)->SL3CFG = pADCState->registerState.regSL3CFG; ADCn(ui32Module)->SL4CFG = pADCState->registerState.regSL4CFG; ADCn(ui32Module)->SL5CFG = pADCState->registerState.regSL5CFG; ADCn(ui32Module)->SL6CFG = pADCState->registerState.regSL6CFG; ADCn(ui32Module)->SL7CFG = pADCState->registerState.regSL7CFG; ADCn(ui32Module)->WULIM = pADCState->registerState.regWULIM; ADCn(ui32Module)->WLLIM = pADCState->registerState.regWLLIM; ADCn(ui32Module)->INTEN = 0; ADCn(ui32Module)->CFG = pADCState->registerState.regCFG & (~ADC_CFG_ADCEN_Msk); ADCn(ui32Module)->CFG_b.ADCEN = _FLD2VAL(ADC_CFG_ADCEN, pADCState->registerState.regCFG); ADCn(ui32Module)->INTEN = pADCState->registerState.regINTEN; pADCState->registerState.bValid = false; } break; case AM_HAL_SYSCTRL_NORMALSLEEP: case AM_HAL_SYSCTRL_DEEPSLEEP: if ( bRetainState ) { pADCState->registerState.regSL0CFG = ADCn(ui32Module)->SL0CFG; pADCState->registerState.regSL1CFG = ADCn(ui32Module)->SL1CFG; pADCState->registerState.regSL2CFG = ADCn(ui32Module)->SL2CFG; pADCState->registerState.regSL3CFG = ADCn(ui32Module)->SL3CFG; pADCState->registerState.regSL4CFG = ADCn(ui32Module)->SL4CFG; pADCState->registerState.regSL5CFG = ADCn(ui32Module)->SL5CFG; pADCState->registerState.regSL6CFG = ADCn(ui32Module)->SL6CFG; pADCState->registerState.regSL7CFG = ADCn(ui32Module)->SL7CFG; pADCState->registerState.regWULIM = ADCn(ui32Module)->WULIM; pADCState->registerState.regWLLIM = ADCn(ui32Module)->WLLIM; pADCState->registerState.regINTEN = ADCn(ui32Module)->INTEN; pADCState->registerState.regCFG = ADCn(ui32Module)->CFG; pADCState->registerState.bValid = true; } // // Disable the ADC power domain. // am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); break; default: return AM_HAL_STATUS_INVALID_ARG; } // // Return the status. // return AM_HAL_STATUS_SUCCESS; } //***************************************************************************** // // End Doxygen group. //! @} // //*****************************************************************************