]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libchip_samv7/source/afec.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libchip_samv7 / source / afec.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2014, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\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
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\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
16  *\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
28  */\r
29 \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
33  * \n\r
34  *\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
37  *\r
38  * To Enable a AFE conversion,the user has to follow these few steps:\r
39  * <ul>\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
48  *      in AFEC_MR.\r
49  </li>\r
50  * <li> Start conversion by setting AFEC_CR_START in AFEC_CR. </li>\r
51  * </ul>\r
52  *\r
53  * For more accurate information, please look at the AFE section of the\r
54  * Datasheet.\r
55  *\r
56  * Related files :\n\r
57  * \ref AFE.c\n\r
58  * \ref AFE.h\n\r
59  */\r
60 /*@{*/\r
61 /*@}*/\r
62 /**\r
63  * \file\r
64  *\r
65  * Implementation of Analog-to-Digital Converter (AFE).\r
66  *\r
67  */\r
68 /*----------------------------------------------------------------------------\r
69  *        Headers\r
70  *----------------------------------------------------------------------------*/\r
71 \r
72 #include "chip.h"\r
73 \r
74 \r
75 /*----------------------------------------------------------------------------\r
76  *        Local variables\r
77  *----------------------------------------------------------------------------*/\r
78 \r
79 /** Current working clock */\r
80 static uint32_t dwAFEClock = 0;\r
81 \r
82 /*----------------------------------------------------------------------------\r
83  *        Exported functions\r
84  *----------------------------------------------------------------------------*/\r
85 \r
86 /**\r
87  * \brief Initialize the AFE controller\r
88  *\r
89  * \param pAFE Pointer to an AFE instance.\r
90  * \param dwID AFE Index\r
91  */\r
92 extern void AFEC_Initialize( Afec* pAFE, uint32_t dwID )\r
93 {\r
94     /* Enable peripheral clock*/\r
95     PMC_EnablePeripheral(dwID);\r
96 \r
97     /*  Reset the controller */\r
98     pAFE->AFEC_CR = AFEC_CR_SWRST;\r
99 \r
100     /* Reset Mode Register */\r
101     pAFE->AFEC_MR = 0;\r
102 }\r
103 \r
104 /**\r
105  * \brief Set AFE clock.\r
106  *\r
107  * \param pAFE Pointer to an AFE instance.\r
108  * \param dwPres prescal value\r
109  * \param dwMck Board MCK (Hz)\r
110  *\r
111  * \return AFE clock\r
112  */\r
113 \r
114 extern uint32_t AFEC_SetClock( Afec* pAFE, uint32_t dwClk, uint32_t dwMck )\r
115\r
116     uint32_t dwPres, dwMr;\r
117     /* Formula for PRESCAL is:\r
118        PRESCAL = peripheral clock/ fAFE Clock - 1 */\r
119 \r
120     dwPres = (dwMck) / (dwClk ) - 1;\r
121     dwMr = AFEC_MR_PRESCAL(dwPres);\r
122     if (dwMr == 0) return 0;\r
123 \r
124     dwMr |= (pAFE->AFEC_MR & ~AFEC_MR_PRESCAL_Msk);\r
125     pAFE->AFEC_MR = dwMr;\r
126     dwAFEClock = dwMck / (dwPres + 1);\r
127     return dwAFEClock;\r
128 }\r
129 \r
130 /**\r
131  * \brief Set AFE timing.\r
132  *\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
137  */\r
138 extern void AFEC_SetTiming( Afec* pAFE, uint32_t dwStartup, uint32_t dwTracking, uint32_t dwSettling )\r
139 {\r
140     uint32_t dwMr;\r
141 \r
142     dwMr = pAFE->AFEC_MR;\r
143     dwMr &= (~AFEC_MR_STARTUP_Msk) & (~AFEC_MR_TRACKTIM_Msk) & (~AFEC_MR_SETTLING_Msk);\r
144 \r
145     /* Formula:\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
150      */\r
151     dwMr |= dwStartup | dwTracking | dwSettling;\r
152     pAFE->AFEC_MR |= dwMr;\r
153 }\r
154 \r
155 /**\r
156  * \brief Set AFE trigger.\r
157  *\r
158  * \param pAFE Pointer to an AFE instance.\r
159  * \param dwTrgSel Trigger selection\r
160  */\r
161 extern void AFEC_SetTrigger( Afec* pAFE, uint32_t dwTrgSel )\r
162 {\r
163     uint32_t dwMr;\r
164 \r
165     dwMr = pAFE->AFEC_MR;\r
166     dwMr &= ~AFEC_MR_TRGSEL_Msk;\r
167     dwMr |= dwTrgSel;\r
168     pAFE->AFEC_MR |= dwMr;\r
169 }\r
170 \r
171 \r
172 /**\r
173  * \brief Enable/Disable sleep mode.\r
174  *\r
175  * \param pAFE Pointer to an AFE instance.\r
176  * \param bEnDis Enable/Disable sleep mode.\r
177  */\r
178 extern void AFEC_SetSleepMode( Afec *pAFE, uint8_t bEnDis )\r
179 {\r
180     if ( bEnDis )\r
181     {\r
182         pAFE->AFEC_MR |=  AFEC_MR_SLEEP;\r
183     }\r
184     else\r
185     {\r
186         pAFE->AFEC_MR &= ~AFEC_MR_SLEEP;\r
187     }\r
188 }\r
189 \r
190 /**\r
191  * \brief Enable/Disable fast wake up.\r
192  *\r
193  * \param pAFE Pointer to an AFE instance.\r
194  * \param bEnDis Enable/Disable fast wake up in sleep mode.\r
195  */\r
196 extern void AFEC_SetFastWakeup( Afec *pAFE, uint8_t bEnDis )\r
197 {\r
198     if ( bEnDis )\r
199     {\r
200         pAFE->AFEC_MR |=  AFEC_MR_FWUP;\r
201     }\r
202     else\r
203     {\r
204         pAFE->AFEC_MR &= ~AFEC_MR_FWUP;\r
205     }\r
206 }\r
207 \r
208 /**\r
209  * \brief Enable/Disable seqnence mode.\r
210  *\r
211  * \param pAFE  Pointer to an AFE instance.\r
212  * \param bEnDis Enable/Disable seqnence mode.\r
213  */\r
214 extern void AFEC_SetSequenceMode( Afec *pAFE, uint8_t bEnDis )\r
215 {\r
216     if ( bEnDis )\r
217     {\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
221     }\r
222     else\r
223     {\r
224         /* Normal Mode: The controller converts channels in a simple numeric order. */\r
225         pAFE->AFEC_MR &= ~AFEC_MR_USEQ;\r
226     }\r
227 }\r
228 \r
229 /**\r
230  * \brief Set channel sequence.\r
231  *\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
235  */\r
236 extern void AFEC_SetSequence( Afec *pAFE, uint32_t dwSEQ1, uint32_t dwSEQ2 )\r
237 {\r
238     pAFE->AFEC_SEQ1R = dwSEQ1;\r
239     pAFE->AFEC_SEQ2R = dwSEQ2;\r
240 }\r
241 \r
242 /**\r
243  * \brief Set channel sequence by given channel list.\r
244  *\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
248  */\r
249 extern void AFEC_SetSequenceByList( Afec *pAFE, uint8_t ucChList[], uint8_t ucNumCh )\r
250 {\r
251     uint8_t i;\r
252     uint8_t ucShift;\r
253 \r
254     pAFE->AFEC_SEQ1R = 0;\r
255     for (i = 0, ucShift = 0; i < 8; i ++, ucShift += 4)\r
256     {\r
257         if (i >= ucNumCh) return;\r
258         pAFE->AFEC_SEQ1R |= ucChList[i] << ucShift;\r
259 \r
260     }\r
261     pAFE->AFEC_SEQ2R = 0;\r
262     for (ucShift = 0; i < 16; i ++, ucShift += 4)\r
263     {\r
264         if (i >= ucNumCh) return;\r
265         pAFE->AFEC_SEQ2R |= ucChList[i] << ucShift;\r
266     }\r
267 }\r
268 \r
269 /**\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
273  *\r
274  * \param pAFE   Pointer to an AFE instance.\r
275  * \param bEnDis Enable/Disable.\r
276  */\r
277 extern void AFEC_SetAnalogChange( Afec* pAFE, uint8_t bEnDis )\r
278 {\r
279     if ( bEnDis )\r
280     {\r
281         pAFE->AFEC_MR |=  AFEC_MR_ANACH;\r
282     }\r
283     else\r
284     {\r
285         pAFE->AFEC_MR &= ~AFEC_MR_ANACH;\r
286     }\r
287 }\r
288 \r
289 /**\r
290  * \brief Set "TAG" mode, show channel number in last data or not.\r
291  *\r
292  * \param pAFE   Pointer to an AFE instance.\r
293  * \param bEnDis Enable/Disable TAG value.\r
294  */\r
295 extern void AFEC_SetTagEnable( Afec *pAFE, uint8_t bEnDis )\r
296 {\r
297     if ( bEnDis )\r
298     {\r
299         pAFE->AFEC_EMR |=  AFEC_EMR_TAG;\r
300     }\r
301     else\r
302     {\r
303         pAFE->AFEC_EMR &= ~AFEC_EMR_TAG;\r
304     }\r
305 }\r
306 \r
307 /**\r
308  * \brief Set compare channel.\r
309  *\r
310  * \param pAFE Pointer to an AFE instance.\r
311  * \param dwChannel channel number to be set,16 for all channels\r
312  */\r
313 extern void AFEC_SetCompareChannel( Afec* pAFE, uint32_t dwChannel )\r
314 {\r
315     assert( dwChannel <= 16 ) ;\r
316 \r
317     if ( dwChannel < 16 )\r
318     {\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
322     }\r
323     else\r
324     {\r
325         pAFE->AFEC_EMR |= AFEC_EMR_CMPALL;\r
326     }\r
327 }\r
328 \r
329 /**\r
330  * \brief Set compare mode.\r
331  *\r
332  * \param pAFE Pointer to an AFE instance.\r
333  * \param dwMode compare mode\r
334  */\r
335 extern void AFEC_SetCompareMode( Afec* pAFE, uint32_t dwMode )\r
336 {\r
337     pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPMODE_Msk);\r
338     pAFE->AFEC_EMR |= (dwMode & AFEC_EMR_CMPMODE_Msk);\r
339 }\r
340 \r
341 /**\r
342  * \brief Set comparsion window.\r
343  *\r
344  * \param pAFE Pointer to an AFE instance.\r
345  * \param dwHi_Lo Comparison Window\r
346  */\r
347 extern void AFEC_SetComparisonWindow( Afec* pAFE, uint32_t dwHi_Lo )\r
348 {\r
349     pAFE->AFEC_CWR = dwHi_Lo ;\r
350 }\r
351 \r
352 \r
353 /**\r
354  * \brief Return the Channel Converted Data\r
355  *\r
356  * \param pAFE Pointer to an AFE instance.\r
357  * \param dwChannel channel to get converted value\r
358  */\r
359 extern uint32_t AFEC_GetConvertedData( Afec* pAFE, uint32_t dwChannel )\r
360 {\r
361     uint32_t dwData = 0;\r
362     assert( dwChannel < 12 ) ;\r
363     pAFE->AFEC_CSELR = dwChannel;\r
364     dwData = pAFE->AFEC_CDR;\r
365 \r
366     return dwData ;\r
367 }\r
368 \r
369 \r
370 /**\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
374  */\r
375 void AFEC_SetStartupTime( Afec *pAFE, uint32_t dwUs )\r
376 {\r
377     uint32_t dwStart;\r
378     uint32_t dwMr;\r
379 \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
384 \r
385     dwStart = (dwUs * dwAFEClock) / (100000);\r
386     if (dwStart % 10) dwStart /= 10;\r
387     else\r
388     {\r
389         dwStart /= 10;\r
390         if (dwStart) dwStart --;\r
391     }\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
408 \r
409     dwMr |= pAFE->AFEC_MR & ~AFEC_MR_STARTUP_Msk;\r
410     pAFE->AFEC_MR = dwMr;\r
411 }\r
412 \r
413 \r
414 /**\r
415  * Set AFE tracking time\r
416  * \param pAFE  Pointer to an AFE instance.\r
417  * \param dwNs  Tracking time in nS.\r
418  */\r
419 void AFEC_SetTrackingTime( Afec *pAFE, uint32_t dwNs )\r
420 {\r
421     uint32_t dwShtim;\r
422     uint32_t dwMr;\r
423 \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
431     else\r
432     {\r
433         dwShtim /= 10;\r
434         if (dwShtim) dwShtim --;\r
435     }\r
436     dwMr  = AFEC_MR_TRACKTIM(dwShtim);\r
437     dwMr |= pAFE->AFEC_MR & ~AFEC_MR_TRACKTIM_Msk;\r
438     pAFE->AFEC_MR = dwMr;\r
439 }\r
440 \r
441 /**\r
442  * \brief Set analog offset to be used for channel CSEL.\r
443  *\r
444  * \param afec  Base address of the AFEC.\r
445  * \param dwChannel AFEC channel number.\r
446  * \param aoffset  Analog offset value.\r
447  */\r
448 void AFEC_SetAnalogOffset( Afec *pAFE, uint32_t dwChannel,uint32_t aoffset )\r
449 {\r
450     assert( dwChannel < 12 ) ;\r
451     pAFE->AFEC_CSELR = dwChannel;\r
452     pAFE->AFEC_COCR = (aoffset & AFEC_COCR_AOFF_Msk);;\r
453 }\r
454 \r
455 /**\r
456  * \brief Set analog offset to be used for channel CSEL.\r
457  *\r
458  * \param afec  Base address of the AFEC.\r
459  * \param control  Analog control value.\r
460  */\r
461 void AFEC_SetAnalogControl( Afec *pAFE, uint32_t control)\r
462 {\r
463     pAFE->AFEC_ACR = control;\r
464 }\r
465 \r
466 \r