1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2014, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
30 /** \addtogroup AFEC_module Working with AFE
\r
31 * \ingroup peripherals_module
\r
32 * The AFE driver provides the interface to configure and use the AFE peripheral.
\r
35 * It converts the analog input to digital format. The converted result could be
\r
36 * 12bit or 10bit. The AFE supports up to 16 analog lines.
\r
38 * To Enable a AFE conversion,the user has to follow these few steps:
\r
40 * <li> Select an appropriate reference voltage on ADVREF </li>
\r
41 * <li> Configure the AFE according to its requirements and special needs,which
\r
42 * could be broken down into several parts:
\r
43 * -# Select the resolution by setting or clearing AFEC_MR_LOWRES bit in
\r
44 * AFEC_MR (Mode Register)
\r
45 * -# Set AFE clock by setting AFEC_MR_PRESCAL bits in AFEC_MR, the clock is
\r
46 * calculated with AFEClock = MCK / ( (PRESCAL+1) * 2 )
\r
47 * -# Set Startup Time,Tracking Clock cycles and Transfer Clock respectively
\r
50 * <li> Start conversion by setting AFEC_CR_START in AFEC_CR. </li>
\r
53 * For more accurate information, please look at the AFE section of the
\r
65 * Implementation of Analog-to-Digital Converter (AFE).
\r
68 /*----------------------------------------------------------------------------
\r
70 *----------------------------------------------------------------------------*/
\r
75 /*----------------------------------------------------------------------------
\r
77 *----------------------------------------------------------------------------*/
\r
79 /** Current working clock */
\r
80 static uint32_t dwAFEClock = 0;
\r
82 /*----------------------------------------------------------------------------
\r
83 * Exported functions
\r
84 *----------------------------------------------------------------------------*/
\r
87 * \brief Initialize the AFE controller
\r
89 * \param pAFE Pointer to an AFE instance.
\r
90 * \param dwID AFE Index
\r
92 extern void AFEC_Initialize( Afec* pAFE, uint32_t dwID )
\r
94 /* Enable peripheral clock*/
\r
95 PMC_EnablePeripheral(dwID);
\r
97 /* Reset the controller */
\r
98 pAFE->AFEC_CR = AFEC_CR_SWRST;
\r
100 /* Reset Mode Register */
\r
105 * \brief Set AFE clock.
\r
107 * \param pAFE Pointer to an AFE instance.
\r
108 * \param dwPres prescal value
\r
109 * \param dwMck Board MCK (Hz)
\r
111 * \return AFE clock
\r
114 extern uint32_t AFEC_SetClock( Afec* pAFE, uint32_t dwClk, uint32_t dwMck )
\r
116 uint32_t dwPres, dwMr;
\r
117 /* Formula for PRESCAL is:
\r
118 PRESCAL = peripheral clock/ fAFE Clock - 1 */
\r
120 dwPres = (dwMck) / (dwClk ) - 1;
\r
121 dwMr = AFEC_MR_PRESCAL(dwPres);
\r
122 if (dwMr == 0) return 0;
\r
124 dwMr |= (pAFE->AFEC_MR & ~AFEC_MR_PRESCAL_Msk);
\r
125 pAFE->AFEC_MR = dwMr;
\r
126 dwAFEClock = dwMck / (dwPres + 1);
\r
131 * \brief Set AFE timing.
\r
133 * \param pAFE Pointer to an AFE instance.
\r
134 * \param dwStartup startup value
\r
135 * \param dwTracking tracking value
\r
136 * \param dwSettling settling value
\r
138 extern void AFEC_SetTiming( Afec* pAFE, uint32_t dwStartup, uint32_t dwTracking, uint32_t dwSettling )
\r
142 dwMr = pAFE->AFEC_MR;
\r
143 dwMr &= (~AFEC_MR_STARTUP_Msk) & (~AFEC_MR_TRACKTIM_Msk) & (~AFEC_MR_SETTLING_Msk);
\r
146 * Startup Time = startup value / AFEClock
\r
147 * Transfer Time = (TRANSFER * 2 + 3) / AFEClock
\r
148 * Tracking Time = (TRACKTIM + 1) / AFEClock
\r
149 * Settling Time = settling value / AFEClock
\r
151 dwMr |= dwStartup | dwTracking | dwSettling;
\r
152 pAFE->AFEC_MR |= dwMr;
\r
156 * \brief Set AFE trigger.
\r
158 * \param pAFE Pointer to an AFE instance.
\r
159 * \param dwTrgSel Trigger selection
\r
161 extern void AFEC_SetTrigger( Afec* pAFE, uint32_t dwTrgSel )
\r
165 dwMr = pAFE->AFEC_MR;
\r
166 dwMr &= ~AFEC_MR_TRGSEL_Msk;
\r
168 pAFE->AFEC_MR |= dwMr;
\r
173 * \brief Enable/Disable sleep mode.
\r
175 * \param pAFE Pointer to an AFE instance.
\r
176 * \param bEnDis Enable/Disable sleep mode.
\r
178 extern void AFEC_SetSleepMode( Afec *pAFE, uint8_t bEnDis )
\r
182 pAFE->AFEC_MR |= AFEC_MR_SLEEP;
\r
186 pAFE->AFEC_MR &= ~AFEC_MR_SLEEP;
\r
191 * \brief Enable/Disable fast wake up.
\r
193 * \param pAFE Pointer to an AFE instance.
\r
194 * \param bEnDis Enable/Disable fast wake up in sleep mode.
\r
196 extern void AFEC_SetFastWakeup( Afec *pAFE, uint8_t bEnDis )
\r
200 pAFE->AFEC_MR |= AFEC_MR_FWUP;
\r
204 pAFE->AFEC_MR &= ~AFEC_MR_FWUP;
\r
209 * \brief Enable/Disable seqnence mode.
\r
211 * \param pAFE Pointer to an AFE instance.
\r
212 * \param bEnDis Enable/Disable seqnence mode.
\r
214 extern void AFEC_SetSequenceMode( Afec *pAFE, uint8_t bEnDis )
\r
218 /* User Sequence Mode: The sequence respects what is defined in
\r
219 AFEC_SEQR1 and AFEC_SEQR2 */
\r
220 pAFE->AFEC_MR |= AFEC_MR_USEQ;
\r
224 /* Normal Mode: The controller converts channels in a simple numeric order. */
\r
225 pAFE->AFEC_MR &= ~AFEC_MR_USEQ;
\r
230 * \brief Set channel sequence.
\r
232 * \param pAFE Pointer to an AFE instance.
\r
233 * \param dwSEQ1 Sequence 1 ~ 8 channel number.
\r
234 * \param dwSEQ2 Sequence 9 ~ 16 channel number.
\r
236 extern void AFEC_SetSequence( Afec *pAFE, uint32_t dwSEQ1, uint32_t dwSEQ2 )
\r
238 pAFE->AFEC_SEQ1R = dwSEQ1;
\r
239 pAFE->AFEC_SEQ2R = dwSEQ2;
\r
243 * \brief Set channel sequence by given channel list.
\r
245 * \param pAFE Pointer to an AFE instance.
\r
246 * \param ucChList Channel list.
\r
247 * \param ucNumCh Number of channels in list.
\r
249 extern void AFEC_SetSequenceByList( Afec *pAFE, uint8_t ucChList[], uint8_t ucNumCh )
\r
254 pAFE->AFEC_SEQ1R = 0;
\r
255 for (i = 0, ucShift = 0; i < 8; i ++, ucShift += 4)
\r
257 if (i >= ucNumCh) return;
\r
258 pAFE->AFEC_SEQ1R |= ucChList[i] << ucShift;
\r
261 pAFE->AFEC_SEQ2R = 0;
\r
262 for (ucShift = 0; i < 16; i ++, ucShift += 4)
\r
264 if (i >= ucNumCh) return;
\r
265 pAFE->AFEC_SEQ2R |= ucChList[i] << ucShift;
\r
270 * \brief Set analog change.
\r
271 * IF enabled, it allows different analog settings for each channel,
\r
272 * otherwise, DIFF0, GAIN0 and OFF0 are used for all channels.
\r
274 * \param pAFE Pointer to an AFE instance.
\r
275 * \param bEnDis Enable/Disable.
\r
277 extern void AFEC_SetAnalogChange( Afec* pAFE, uint8_t bEnDis )
\r
281 pAFE->AFEC_MR |= AFEC_MR_ANACH;
\r
285 pAFE->AFEC_MR &= ~AFEC_MR_ANACH;
\r
290 * \brief Set "TAG" mode, show channel number in last data or not.
\r
292 * \param pAFE Pointer to an AFE instance.
\r
293 * \param bEnDis Enable/Disable TAG value.
\r
295 extern void AFEC_SetTagEnable( Afec *pAFE, uint8_t bEnDis )
\r
299 pAFE->AFEC_EMR |= AFEC_EMR_TAG;
\r
303 pAFE->AFEC_EMR &= ~AFEC_EMR_TAG;
\r
308 * \brief Set compare channel.
\r
310 * \param pAFE Pointer to an AFE instance.
\r
311 * \param dwChannel channel number to be set,16 for all channels
\r
313 extern void AFEC_SetCompareChannel( Afec* pAFE, uint32_t dwChannel )
\r
315 assert( dwChannel <= 16 ) ;
\r
317 if ( dwChannel < 16 )
\r
319 pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPALL);
\r
320 pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPSEL_Msk);
\r
321 pAFE->AFEC_EMR |= (dwChannel << AFEC_EMR_CMPSEL_Pos);
\r
325 pAFE->AFEC_EMR |= AFEC_EMR_CMPALL;
\r
330 * \brief Set compare mode.
\r
332 * \param pAFE Pointer to an AFE instance.
\r
333 * \param dwMode compare mode
\r
335 extern void AFEC_SetCompareMode( Afec* pAFE, uint32_t dwMode )
\r
337 pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPMODE_Msk);
\r
338 pAFE->AFEC_EMR |= (dwMode & AFEC_EMR_CMPMODE_Msk);
\r
342 * \brief Set comparsion window.
\r
344 * \param pAFE Pointer to an AFE instance.
\r
345 * \param dwHi_Lo Comparison Window
\r
347 extern void AFEC_SetComparisonWindow( Afec* pAFE, uint32_t dwHi_Lo )
\r
349 pAFE->AFEC_CWR = dwHi_Lo ;
\r
354 * \brief Return the Channel Converted Data
\r
356 * \param pAFE Pointer to an AFE instance.
\r
357 * \param dwChannel channel to get converted value
\r
359 extern uint32_t AFEC_GetConvertedData( Afec* pAFE, uint32_t dwChannel )
\r
361 uint32_t dwData = 0;
\r
362 assert( dwChannel < 12 ) ;
\r
363 pAFE->AFEC_CSELR = dwChannel;
\r
364 dwData = pAFE->AFEC_CDR;
\r
371 * Sets the AFE startup time.
\r
372 * \param pAFE Pointer to an AFE instance.
\r
373 * \param dwUs Startup time in uS.
\r
375 void AFEC_SetStartupTime( Afec *pAFE, uint32_t dwUs )
\r
380 if (dwAFEClock == 0) return;
\r
381 /* Formula for STARTUP is:
\r
382 STARTUP = (time x AFECLK) / (1000000) - 1
\r
383 Division multiplied by 10 for higher precision */
\r
385 dwStart = (dwUs * dwAFEClock) / (100000);
\r
386 if (dwStart % 10) dwStart /= 10;
\r
390 if (dwStart) dwStart --;
\r
392 if (dwStart > 896) dwMr = AFEC_MR_STARTUP_SUT960;
\r
393 else if (dwStart > 832) dwMr = AFEC_MR_STARTUP_SUT896;
\r
394 else if (dwStart > 768) dwMr = AFEC_MR_STARTUP_SUT832;
\r
395 else if (dwStart > 704) dwMr = AFEC_MR_STARTUP_SUT768;
\r
396 else if (dwStart > 640) dwMr = AFEC_MR_STARTUP_SUT704;
\r
397 else if (dwStart > 576) dwMr = AFEC_MR_STARTUP_SUT640;
\r
398 else if (dwStart > 512) dwMr = AFEC_MR_STARTUP_SUT576;
\r
399 else if (dwStart > 112) dwMr = AFEC_MR_STARTUP_SUT512;
\r
400 else if (dwStart > 96) dwMr = AFEC_MR_STARTUP_SUT112;
\r
401 else if (dwStart > 80) dwMr = AFEC_MR_STARTUP_SUT96;
\r
402 else if (dwStart > 64) dwMr = AFEC_MR_STARTUP_SUT80;
\r
403 else if (dwStart > 24) dwMr = AFEC_MR_STARTUP_SUT64;
\r
404 else if (dwStart > 16) dwMr = AFEC_MR_STARTUP_SUT24;
\r
405 else if (dwStart > 8) dwMr = AFEC_MR_STARTUP_SUT16;
\r
406 else if (dwStart > 0) dwMr = AFEC_MR_STARTUP_SUT8;
\r
407 else dwMr = AFEC_MR_STARTUP_SUT0;
\r
409 dwMr |= pAFE->AFEC_MR & ~AFEC_MR_STARTUP_Msk;
\r
410 pAFE->AFEC_MR = dwMr;
\r
415 * Set AFE tracking time
\r
416 * \param pAFE Pointer to an AFE instance.
\r
417 * \param dwNs Tracking time in nS.
\r
419 void AFEC_SetTrackingTime( Afec *pAFE, uint32_t dwNs )
\r
424 if (dwAFEClock == 0) return;
\r
425 /* Formula for SHTIM is:
\r
426 SHTIM = (time x AFECLK) / (1000000000) - 1
\r
427 Since 1 billion is close to the maximum value for an integer, we first
\r
428 divide AFECLK by 1000 to avoid an overflow */
\r
429 dwShtim = (dwNs * (dwAFEClock / 1000)) / 100000;
\r
430 if (dwShtim % 10) dwShtim /= 10;
\r
434 if (dwShtim) dwShtim --;
\r
436 dwMr = AFEC_MR_TRACKTIM(dwShtim);
\r
437 dwMr |= pAFE->AFEC_MR & ~AFEC_MR_TRACKTIM_Msk;
\r
438 pAFE->AFEC_MR = dwMr;
\r
442 * \brief Set analog offset to be used for channel CSEL.
\r
444 * \param afec Base address of the AFEC.
\r
445 * \param dwChannel AFEC channel number.
\r
446 * \param aoffset Analog offset value.
\r
448 void AFEC_SetAnalogOffset( Afec *pAFE, uint32_t dwChannel,uint32_t aoffset )
\r
450 assert( dwChannel < 12 ) ;
\r
451 pAFE->AFEC_CSELR = dwChannel;
\r
452 pAFE->AFEC_COCR = (aoffset & AFEC_COCR_AOFF_Msk);;
\r
456 * \brief Set analog offset to be used for channel CSEL.
\r
458 * \param afec Base address of the AFEC.
\r
459 * \param control Analog control value.
\r
461 void AFEC_SetAnalogControl( Afec *pAFE, uint32_t control)
\r
463 pAFE->AFEC_ACR = control;
\r