/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * * All rights reserved. * * 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 disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL 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. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include #ifdef AT91C_BASE_TSADC #include #include //------------------------------------------------------------------------------ // Local variables //------------------------------------------------------------------------------ /// TSADC clock frequency in Hz. static unsigned int lAdcclk = 0; //------------------------------------------------------------------------------ // Global functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Sets the operating mode of the TSADCC peripheral. The mode value can be /// one of the following: /// - AT91C_TSADC_TSAMOD_ADC_ONLY_MODE /// - AT91C_TSADC_TSAMOD_TS_ONLY_MODE /// \param mode Desired mode for the TSADCC. //------------------------------------------------------------------------------ void TSADCC_SetOperatingMode(unsigned int mode) { SANITY_CHECK( (mode == AT91C_TSADC_TSAMOD_ADC_ONLY_MODE) | (mode == AT91C_TSADC_TSAMOD_TS_ONLY_MODE)); AT91C_BASE_TSADC->TSADC_MR = (AT91C_BASE_TSADC->TSADC_MR & ~AT91C_TSADC_TSAMOD) | mode; } //------------------------------------------------------------------------------ /// Enables or disables the low resolution precision on the TSADC. /// \param enable If true, low resolution (8 bit) is used; otherwise the TSADC /// will use a 10-bit resolution. //------------------------------------------------------------------------------ void TSADCC_SetLowResolution(unsigned char enable) { if (enable) { AT91C_BASE_TSADC->TSADC_MR |= AT91C_TSADC_LOWRES; } else { AT91C_BASE_TSADC->TSADC_MR &= ~AT91C_TSADC_LOWRES; } } //------------------------------------------------------------------------------ /// Enables or disable SLEEP mode on the TSADC. /// \param enable If true, the TSADC is put into sleep mode; in normal mode /// otherwise. //------------------------------------------------------------------------------ void TSADCC_SetSleepMode(unsigned char enable) { if (enable) { AT91C_BASE_TSADC->TSADC_MR |= AT91C_TSADC_SLEEP; } else { AT91C_BASE_TSADC->TSADC_MR &= ~AT91C_TSADC_SLEEP; } } //------------------------------------------------------------------------------ /// Enables or disables pen detection on the TSADC. /// \param enable If true, pen detection is enabled; otherwise it is disabled. //------------------------------------------------------------------------------ void TSADCC_SetPenDetect(unsigned char enable) { if (enable) { AT91C_BASE_TSADC->TSADC_MR |= AT91C_TSADC_PENDET; } else { AT91C_BASE_TSADC->TSADC_MR &= ~AT91C_TSADC_PENDET; } } //------------------------------------------------------------------------------ /// Sets the TSADC clock to the desired frequency. The prescaler is calculated /// by this function so the resulting frequency is equal or inferior to the /// desired one. /// \param adcclk Desired ADC clock frequency in Hz. /// \param mck Master clock frequency in Hz. //------------------------------------------------------------------------------ void TSADCC_SetAdcFrequency(unsigned int adcclk, unsigned int mck) { unsigned int prescal; // Formula for PRESCAL is: // PRESCAL = (MCK / (2 * ADCCLK)) + 1 // First, we do the division, multiplied by 10 to get higher precision // If the last digit is not zero, we round up to avoid generating a higher // than required frequency. prescal = (mck * 5) / adcclk; if ((prescal % 10) > 0) { prescal = (prescal / 10); } else { SANITY_CHECK((prescal / 10) != 0); prescal = (prescal / 10) - 1; } SANITY_CHECK(((prescal << 8) & ~AT91C_TSADC_PRESCAL) == 0); AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR & ~AT91C_TSADC_PRESCAL) | (prescal << 8); // Save clock frequency for further timing calculations lAdcclk = adcclk; } //------------------------------------------------------------------------------ /// Sets the TSADC startup time. This function relies on the ADCCLK frequency /// that has been set using TSADCC_SetAdcFrequency(), so it must have been /// called first. /// \param time Startup time in µseconds. //------------------------------------------------------------------------------ void TSADCC_SetStartupTime(unsigned int time) { unsigned int startup; SANITY_CHECK(lAdcclk != 0); // Formula for STARTUP is: // STARTUP = (time x ADCCLK) / (1000000 x 8) - 1 // Division multiplied by 10 for higher precision startup = (time * lAdcclk) / (800000); if ((startup % 10) > 0) { startup /= 10; } else { startup /= 10; if (startup > 0) { startup--; } } SANITY_CHECK((startup & ~0x7F) == 0); AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR & ~AT91C_TSADC_STARTUP) | (startup << 16); } //------------------------------------------------------------------------------ /// Sets the TSADC track and hold time. This function relies on the ADCCLK /// frequency that has been set with TSADCC_SetAdcFrequency(), to it must be /// called first. /// This function also sets the track and hold time in the TSADC_TSR register. /// \param time Track and hold time in nanoseconds. //------------------------------------------------------------------------------ void TSADCC_SetTrackAndHoldTime(unsigned int time) { unsigned int shtim; SANITY_CHECK(lAdcclk != 0); // Formula for SHTIM: // SHTIM = (time x ADCCLK) / 1000000000 - 1 // Since 1 billion is close to the maximum value for an integer, we first // divide ADCCLK by 1000 to avoid an overflow shtim = (time * (lAdcclk / 1000)) / 100000; if ((shtim % 10) > 0) { shtim /= 10; } else { shtim /= 10; if (shtim > 0) shtim--; } SANITY_CHECK((shtim & ~0xF) == 0); AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR & ~AT91C_TSADC_SHTIM) | (shtim << 24); AT91C_BASE_TSADC->TSADC_TSR = shtim << 24; } //------------------------------------------------------------------------------ /// Sets the TSADC debounce time. This function relies on the ADCCLK /// frequency that has been set with TSADCC_SetAdcFrequency(), to it must be /// called first. /// \param time Debounce time in nanoseconds (cannot be 0). //------------------------------------------------------------------------------ void TSADCC_SetDebounceTime(unsigned int time) { unsigned int divisor = 1000000000; unsigned int clock = lAdcclk; unsigned int pendbc = 0; unsigned int targetValue; unsigned int currentValue; SANITY_CHECK(lAdcclk != 0); SANITY_CHECK(time != 0); // Divide time & ADCCLK first to avoid overflows while ((divisor > 1) && ((time % 10) == 0)) { time /= 10; divisor /= 10; } while ((divisor > 1) && ((clock % 10) == 0)) { clock /= 10; divisor /= 10; } // Compute PENDBC value targetValue = time * clock / divisor; currentValue = 1; while (currentValue < targetValue) { pendbc++; currentValue *= 2; } SANITY_CHECK((pendbc & ~0xF) == 0); AT91C_BASE_TSADC->TSADC_MR = ( AT91C_BASE_TSADC->TSADC_MR & ~AT91C_TSADC_PENDBC) | (pendbc << 28); } //------------------------------------------------------------------------------ /// Sets the trigger mode of the TSADCC to one of the following values: /// - AT91C_TSADC_TRGMOD_NO_TRIGGER /// - AT91C_TSADC_TRGMOD_EXTERNAL_TRIGGER_RE /// - AT91C_TSADC_TRGMOD_EXTERNAL_TRIGGER_FE /// - AT91C_TSADC_TRGMOD_EXTERNAL_TRIGGER_AE /// - AT91C_TSADC_TRGMOD_PENDET_TRIGGER /// - AT91C_TSADC_TRGMOD_PERIODIC_TRIGGER /// - AT91C_TSADC_TRGMOD_CONT_TRIGGER /// \param mode Trigger mode. //------------------------------------------------------------------------------ void TSADCC_SetTriggerMode(unsigned int mode) { SANITY_CHECK(((mode & ~AT91C_TSADC_TRGMOD) == 0) | ((mode & AT91C_TSADC_TRGMOD) != 0x7)); AT91C_BASE_TSADC->TSADC_TRGR = (AT91C_BASE_TSADC->TSADC_TRGR & ~AT91C_TSADC_TRGMOD) | mode; } //------------------------------------------------------------------------------ /// Sets the trigger period when using the TSADCC in periodic trigger mode. /// As usual, this function requires TSADCC_SetAdcFrequency() to be called /// before it. /// \param period Trigger period in nanoseconds. //------------------------------------------------------------------------------ void TSADCC_SetTriggerPeriod(unsigned int period) { unsigned int trgper; unsigned int divisor = 100000000; while ((period >= 10) && (divisor >= 10)) { period /= 10; divisor /= 10; } trgper = (period * lAdcclk) / divisor; if ((trgper % 10) > 0) { trgper /= 10; } else { trgper /= 10; if (trgper > 0) trgper--; } SANITY_CHECK((trgper & ~0xFFFF) == 0); AT91C_BASE_TSADC->TSADC_TRGR = (AT91C_BASE_TSADC->TSADC_TRGR & ~AT91C_TSADC_TRGPER) | (trgper << 16); } #endif //#ifdef AT91C_BASE_TSADC