/* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 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. * * Neither the name of Texas Instruments Incorporated 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 * OWNER 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. * */ //***************************************************************************** // // adc.c // // Driver for the ADC module. // //***************************************************************************** //***************************************************************************** // //! \addtogroup ADC_Analog_to_Digital_Converter_api //! @{ // //***************************************************************************** #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "inc/hw_ints.h" #include "inc/hw_adc.h" #include "inc/hw_apps_config.h" #include "interrupt.h" #include "adc.h" //***************************************************************************** // //! Enables the ADC //! //! \param ulBase is the base address of the ADC //! //! This function sets the ADC global enable //! //! \return None. // //***************************************************************************** void ADCEnable(unsigned long ulBase) { // // Set the global enable bit in the control register. // HWREG(ulBase + ADC_O_ADC_CTRL) |= 0x1; } //***************************************************************************** // //! Disable the ADC //! //! \param ulBase is the base address of the ADC //! //! This function clears the ADC global enable //! //! \return None. // //***************************************************************************** void ADCDisable(unsigned long ulBase) { // // Clear the global enable bit in the control register. // HWREG(ulBase + ADC_O_ADC_CTRL) &= ~0x1 ; } //***************************************************************************** // //! Enables specified ADC channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! //! This function enables specified ADC channel and configures the //! pin as analog pin. //! //! \return None. // //***************************************************************************** void ADCChannelEnable(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulCh; ulCh = (ulChannel == ADC_CH_0)? 0x02 : (ulChannel == ADC_CH_1)? 0x04 : (ulChannel == ADC_CH_2)? 0x08 : 0x10; HWREG(ulBase + ADC_O_ADC_CH_ENABLE) |= ulCh; } //***************************************************************************** // //! Disables specified ADC channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channelsber //! //! This function disables specified ADC channel. //! //! \return None. // //***************************************************************************** void ADCChannelDisable(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulCh; ulCh = (ulChannel == ADC_CH_0)? 0x02 : (ulChannel == ADC_CH_1)? 0x04 : (ulChannel == ADC_CH_2)? 0x08 : 0x10; HWREG(ulBase + ADC_O_ADC_CH_ENABLE) &= ~ulCh; } //***************************************************************************** // //! Enables and registers ADC interrupt handler for specified channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! \param pfnHandler is a pointer to the function to be called when the //! ADC channel interrupt occurs. //! //! This function enables and registers ADC interrupt handler for specified //! channel. Individual interrupt for each channel should be enabled using //! \sa ADCIntEnable(). It is the interrupt handler's responsibility to clear //! the interrupt source. //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! \return None. // //***************************************************************************** void ADCIntRegister(unsigned long ulBase, unsigned long ulChannel, void (*pfnHandler)(void)) { unsigned long ulIntNo; // // Get the interrupt number associted with the specified channel // ulIntNo = (ulChannel == ADC_CH_0)? INT_ADCCH0 : (ulChannel == ADC_CH_1)? INT_ADCCH1 : (ulChannel == ADC_CH_2)? INT_ADCCH2 : INT_ADCCH3; // // Register the interrupt handler // IntRegister(ulIntNo,pfnHandler); // // Enable ADC interrupt // IntEnable(ulIntNo); } //***************************************************************************** // //! Disables and unregisters ADC interrupt handler for specified channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! //! This function disables and unregisters ADC interrupt handler for specified //! channel. This function also masks off the interrupt in the interrupt //! controller so that the interrupt handler no longer is called. //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! \return None. // //***************************************************************************** void ADCIntUnregister(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulIntNo; // // Get the interrupt number associted with the specified channel // ulIntNo = (ulChannel == ADC_CH_0)? INT_ADCCH0 : (ulChannel == ADC_CH_1)? INT_ADCCH1 : (ulChannel == ADC_CH_2)? INT_ADCCH2 : INT_ADCCH3; // // Disable ADC interrupt // IntDisable(ulIntNo); // // Unregister the interrupt handler // IntUnregister(ulIntNo); } //***************************************************************************** // //! Enables individual interrupt sources for specified channel //! //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. //! //! This function enables the indicated ADC interrupt sources. Only the //! sources that are enabled can be reflected to the processor interrupt; //! disabled sources have no effect on the processor. //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! The \e ulIntFlags parameter is the logical OR of any of the following: //! - \b ADC_DMA_DONE for DMA done //! - \b ADC_FIFO_OVERFLOW for FIFO over flow //! - \b ADC_FIFO_UNDERFLOW for FIFO under flow //! - \b ADC_FIFO_EMPTY for FIFO empty //! - \b ADC_FIFO_FULL for FIFO full //! //! \return None. // //***************************************************************************** void ADCIntEnable(unsigned long ulBase, unsigned long ulChannel, unsigned long ulIntFlags) { unsigned long ulOffset; unsigned long ulDmaMsk; // // Enable DMA Done interrupt // if(ulIntFlags & ADC_DMA_DONE) { ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: (ulChannel == ADC_CH_1)?0x00002000: (ulChannel == ADC_CH_2)?0x00004000:0x00008000; HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = ulDmaMsk; } ulIntFlags = ulIntFlags & 0x0F; // // Get the interrupt enable register offset for specified channel // ulOffset = ADC_O_adc_ch0_irq_en + ulChannel; // // Unmask the specified interrupts // HWREG(ulBase + ulOffset) |= (ulIntFlags & 0xf); } //***************************************************************************** // //! Disables individual interrupt sources for specified channel //! //! //! \param ulBase is the base address of the ADC. //! \param ulChannel is one of the valid ADC channels //! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. //! //! This function disables the indicated ADC interrupt sources. Only the //! sources that are enabled can be reflected to the processor interrupt; //! disabled sources have no effect on the processor. //! //! The parameters\e ulIntFlags and \e ulChannel should be as explained in //! ADCIntEnable(). //! //! \return None. // //***************************************************************************** void ADCIntDisable(unsigned long ulBase, unsigned long ulChannel, unsigned long ulIntFlags) { unsigned long ulOffset; unsigned long ulDmaMsk; // // Disable DMA Done interrupt // if(ulIntFlags & ADC_DMA_DONE) { ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: (ulChannel == ADC_CH_1)?0x00002000: (ulChannel == ADC_CH_2)?0x00004000:0x00008000; HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = ulDmaMsk; } // // Get the interrupt enable register offset for specified channel // ulOffset = ADC_O_adc_ch0_irq_en + ulChannel; // // Unmask the specified interrupts // HWREG(ulBase + ulOffset) &= ~ulIntFlags; } //***************************************************************************** // //! Gets the current channel interrupt status //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! //! This function returns the interrupt status of the specified ADC channel. //! //! The parameter \e ulChannel should be as explained in \sa ADCIntEnable(). //! //! \return Return the ADC channel interrupt status, enumerated as a bit //! field of values described in ADCIntEnable() // //***************************************************************************** unsigned long ADCIntStatus(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulOffset; unsigned long ulDmaMsk; unsigned long ulIntStatus; // // Get DMA Done interrupt status // ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: (ulChannel == ADC_CH_1)?0x00002000: (ulChannel == ADC_CH_2)?0x00004000:0x00008000; ulIntStatus = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_MASKED)& ulDmaMsk; // // Get the interrupt enable register offset for specified channel // ulOffset = ADC_O_adc_ch0_irq_status + ulChannel; // // Read ADC interrupt status // ulIntStatus |= HWREG(ulBase + ulOffset) & 0xf; // // Return the current interrupt status // return(ulIntStatus); } //***************************************************************************** // //! Clears the current channel interrupt sources //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! \param ulIntFlags is the bit mask of the interrupt sources to be cleared. //! //! This function clears individual interrupt source for the specified //! ADC channel. //! //! The parameter \e ulChannel should be as explained in \sa ADCIntEnable(). //! //! \return None. // //***************************************************************************** void ADCIntClear(unsigned long ulBase, unsigned long ulChannel, unsigned long ulIntFlags) { unsigned long ulOffset; unsigned long ulDmaMsk; // // Clear DMA Done interrupt // if(ulIntFlags & ADC_DMA_DONE) { ulDmaMsk = (ulChannel == ADC_CH_0)?0x00001000: (ulChannel == ADC_CH_1)?0x00002000: (ulChannel == ADC_CH_2)?0x00004000:0x00008000; HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = ulDmaMsk; } // // Get the interrupt enable register offset for specified channel // ulOffset = ADC_O_adc_ch0_irq_status + ulChannel; // // Clear the specified interrupts // HWREG(ulBase + ulOffset) = (ulIntFlags & ~(ADC_DMA_DONE)); } //***************************************************************************** // //! Enables the ADC DMA operation for specified channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! //! This function enables the DMA operation for specified ADC channel //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! \return None. // //***************************************************************************** void ADCDMAEnable(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulBitMask; // // Get the bit mask for enabling DMA for specified channel // ulBitMask = (ulChannel == ADC_CH_0)?0x01: (ulChannel == ADC_CH_1)?0x04: (ulChannel == ADC_CH_2)?0x10:0x40; // // Enable DMA request for the specified channel // HWREG(ulBase + ADC_O_adc_dma_mode_en) |= ulBitMask; } //***************************************************************************** // //! Disables the ADC DMA operation for specified channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels //! //! This function disables the DMA operation for specified ADC channel //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! \return None. // //***************************************************************************** void ADCDMADisable(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulBitMask; // // Get the bit mask for disabling DMA for specified channel // ulBitMask = (ulChannel == ADC_CH_0)?0x01: (ulChannel == ADC_CH_1)?0x04: (ulChannel == ADC_CH_2)?0x10:0x40; // // Disable DMA request for the specified channel // HWREG(ulBase + ADC_O_adc_dma_mode_en) &= ~ulBitMask; } //***************************************************************************** // //! Configures the ADC internal timer //! //! \param ulBase is the base address of the ADC //! \param ulValue is wrap arround value of the timer //! //! This function Configures the ADC internal timer. The ADC timer is a 17 bit //! used to timestamp the ADC data samples internally. //! User can read the timestamp along with the sample from the FIFO register(s). //! Each sample in the FIFO contains 14 bit actual data and 18 bit timestamp //! //! The parameter \e ulValue can take any value between 0 - 2^17 //! //! \returns None. // //***************************************************************************** void ADCTimerConfig(unsigned long ulBase, unsigned long ulValue) { unsigned long ulReg; // // Read the currrent config // ulReg = HWREG(ulBase + ADC_O_adc_timer_configuration); // // Mask and set timer count field // ulReg = ((ulReg & ~0x1FFFF) | (ulValue & 0x1FFFF)); // // Set the timer count value // HWREG(ulBase + ADC_O_adc_timer_configuration) = ulReg; } //***************************************************************************** // //! Resets ADC internal timer //! //! \param ulBase is the base address of the ADC //! //! This function resets 17-bit ADC internal timer //! //! \returns None. // //***************************************************************************** void ADCTimerReset(unsigned long ulBase) { // // Reset the timer // HWREG(ulBase + ADC_O_adc_timer_configuration) |= (1 << 24); } //***************************************************************************** // //! Enables ADC internal timer //! //! \param ulBase is the base address of the ADC //! //! This function enables 17-bit ADC internal timer //! //! \returns None. // //***************************************************************************** void ADCTimerEnable(unsigned long ulBase) { // // Enable the timer // HWREG(ulBase + ADC_O_adc_timer_configuration) |= (1 << 25); } //***************************************************************************** // //! Disables ADC internal timer //! //! \param ulBase is the base address of the ADC //! //! This function disables 17-bit ADC internal timer //! //! \returns None. // //***************************************************************************** void ADCTimerDisable(unsigned long ulBase) { // // Disable the timer // HWREG(ulBase + ADC_O_adc_timer_configuration) &= ~(1 << 25); } //***************************************************************************** // //! Gets the current value of ADC internal timer //! //! \param ulBase is the base address of the ADC //! //! This function the current value of 17-bit ADC internal timer //! //! \returns Return the current value of ADC internal timer. // //***************************************************************************** unsigned long ADCTimerValueGet(unsigned long ulBase) { return(HWREG(ulBase + ADC_O_adc_timer_current_count)); } //***************************************************************************** // //! Gets the current FIFO level for specified ADC channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels. //! //! This function returns the current FIFO level for specified ADC channel. //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! \returns Return the current FIFO level for specified channel // //***************************************************************************** unsigned char ADCFIFOLvlGet(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulOffset; // // Get the fifo level register offset for specified channel // ulOffset = ADC_O_adc_ch0_fifo_lvl + ulChannel; // // Return FIFO level // return(HWREG(ulBase + ulOffset) & 0x7); } //***************************************************************************** // //! Reads FIFO for specified ADC channel //! //! \param ulBase is the base address of the ADC //! \param ulChannel is one of the valid ADC channels. //! //! This function returns one data sample from the channel fifo as specified by //! \e ulChannel parameter. //! //! The parameter \e ulChannel should be one of the following //! //! - \b ADC_CH_0 for channel 0 //! - \b ADC_CH_1 for channel 1 //! - \b ADC_CH_2 for channel 2 //! - \b ADC_CH_3 for channel 3 //! //! \returns Return one data sample from the channel fifo. // //***************************************************************************** unsigned long ADCFIFORead(unsigned long ulBase, unsigned long ulChannel) { unsigned long ulOffset; // // Get the fifo register offset for specified channel // ulOffset = ADC_O_channel0FIFODATA + ulChannel; // // Return FIFO level // return(HWREG(ulBase + ulOffset)); } //***************************************************************************** // // Close the Doxygen group. //! @} // //*****************************************************************************