source: rtems/bsps/arm/atsam/contrib/libraries/libchip/source/afec.c @ 54aabb7

5
Last change on this file since 54aabb7 was 54aabb7, checked in by Sebastian Huber <sebastian.huber@…>, on 04/22/18 at 13:11:43

bsp/atsam: Move libraries to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 12.7 KB
Line 
1/* ---------------------------------------------------------------------------- */
2/*                  Atmel Microcontroller Software Support                      */
3/*                       SAM Software Package License                           */
4/* ---------------------------------------------------------------------------- */
5/* Copyright (c) 2015, Atmel Corporation                                        */
6/*                                                                              */
7/* All rights reserved.                                                         */
8/*                                                                              */
9/* Redistribution and use in source and binary forms, with or without           */
10/* modification, are permitted provided that the following condition is met:    */
11/*                                                                              */
12/* - Redistributions of source code must retain the above copyright notice,     */
13/* this list of conditions and the disclaimer below.                            */
14/*                                                                              */
15/* Atmel's name may not be used to endorse or promote products derived from     */
16/* this software without specific prior written permission.                     */
17/*                                                                              */
18/* DISCLAIMER:  THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR   */
19/* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */
20/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE   */
21/* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,      */
22/* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
23/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,  */
24/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    */
25/* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING         */
26/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */
27/* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                           */
28/* ---------------------------------------------------------------------------- */
29
30/** \addtogroup AFEC_module Working with AFE
31 * \ingroup peripherals_module
32 * The AFE driver provides the interface to configure and use the AFE peripheral.
33 * \n
34 *
35 * It converts the analog input to digital format. The converted result could be
36 * 12bit or 10bit. The AFE supports up to 16 analog lines.
37 *
38 * To Enable a AFE conversion,the user has to follow these few steps:
39 * <ul>
40 * <li> Select an appropriate reference voltage on ADVREF   </li>
41 * <li> Configure the AFE according to its requirements and special needs,which
42 * could be  broken down into several parts:
43 * -#   Select the resolution by setting or clearing AFEC_MR_LOWRES bit in
44 *      AFEC_MR (Mode Register)
45 * -#   Set AFE clock by setting AFEC_MR_PRESCAL bits in AFEC_MR, the clock is
46 *      calculated with AFEClock = MCK / ((PRESCAL+1) * 2)
47 * -#   Set Startup Time,Tracking Clock cycles and Transfer Clock respectively
48 *      in AFEC_MR.
49 </li>
50 * <li> Start conversion by setting AFEC_CR_START in AFEC_CR. </li>
51 * </ul>
52 *
53 * For more accurate information, please look at the AFE section of the
54 * Datasheet.
55 *
56 * Related files :\n
57 * \ref afec.c\n
58 * \ref afec.h\n
59 * \ref afe_dma.c\n
60 * \ref afe_dma.h\n
61 */
62/*@{*/
63/*@}*/
64/**
65 * \file
66 *
67 * Implementation of Analog-to-Digital Converter (AFE).
68 *
69 */
70/*----------------------------------------------------------------------------
71 *        Headers
72 *----------------------------------------------------------------------------*/
73
74#include "chip.h"
75
76
77/*----------------------------------------------------------------------------
78 *        Local variables
79 *----------------------------------------------------------------------------*/
80
81/** Current working clock */
82static uint32_t dwAFEClock = 0;
83
84/*----------------------------------------------------------------------------
85 *        Exported functions
86 *----------------------------------------------------------------------------*/
87
88/**
89 * \brief Initialize the AFE controller
90 *
91 * \param pAFE Pointer to an AFE instance.
92 * \param dwID AFE Index
93 */
94extern void AFEC_Initialize(Afec *pAFE, uint32_t dwID)
95{
96        /* Enable peripheral clock*/
97        PMC_EnablePeripheral(dwID);
98
99        /*  Reset the controller */
100        pAFE->AFEC_CR = AFEC_CR_SWRST;
101
102        /* Reset Mode Register */
103        pAFE->AFEC_MR = 0;
104}
105
106/**
107 * \brief Set AFE clock.
108 *
109 * \param pAFE Pointer to an AFE instance.
110 * \param dwPres prescale value
111 * \param dwMck Board MCK (Hz)
112 *
113 * \return AFE clock
114 */
115
116extern uint32_t AFEC_SetClock(Afec *pAFE, uint32_t dwClk, uint32_t dwMck)
117{
118        uint32_t dwPres, dwMr;
119        /* Formula for PRESCAL is:
120           PRESCAL = peripheral clock/ fAFE Clock - 1 */
121
122        dwPres = (dwMck) / (dwClk) - 1;
123        dwMr = AFEC_MR_PRESCAL(dwPres);
124
125        if (dwMr == 0) return 0;
126
127        dwMr |= (pAFE->AFEC_MR & ~AFEC_MR_PRESCAL_Msk);
128        pAFE->AFEC_MR = dwMr;
129        dwAFEClock = dwMck / (dwPres + 1);
130        return dwAFEClock;
131}
132
133/**
134 * \brief Set AFE timing.
135 *
136 * \param pAFE Pointer to an AFE instance.
137 * \param dwStartup startup value
138 * \param dwTracking tracking value
139 * \param dwSettling settling value
140 */
141extern void AFEC_SetTiming(Afec *pAFE, uint32_t dwStartup, uint32_t dwTracking,
142                                                        uint32_t dwSettling)
143{
144        uint32_t dwMr;
145
146        dwMr = pAFE->AFEC_MR;
147        dwMr &= (~AFEC_MR_STARTUP_Msk) & (~AFEC_MR_TRACKTIM_Msk) &
148                        (~AFEC_MR_SETTLING_Msk);
149
150        /* Formula:
151         *     Startup  Time = startup value / AFEClock
152         *     Transfer Time = (TRANSFER * 2 + 3) / AFEClock
153         *     Tracking Time = (TRACKTIM + 1) / AFEClock
154         *     Settling Time = settling value / AFEClock
155         */
156        dwMr |= dwStartup | dwTracking | dwSettling;
157        pAFE->AFEC_MR |= dwMr;
158}
159
160/**
161 * \brief Set AFE trigger.
162 *
163 * \param pAFE Pointer to an AFE instance.
164 * \param dwTrgSel Trigger selection
165 */
166extern void AFEC_SetTrigger(Afec *pAFE, uint32_t dwTrgSel)
167{
168        uint32_t dwMr;
169
170        dwMr = pAFE->AFEC_MR;
171        dwMr &= ~AFEC_MR_TRGSEL_Msk;
172        dwMr |= dwTrgSel;
173        pAFE->AFEC_MR |= dwMr;
174}
175
176
177/**
178 * \brief Enable/Disable sleep mode.
179 *
180 * \param pAFE Pointer to an AFE instance.
181 * \param bEnDis Enable/Disable sleep mode.
182 */
183extern void AFEC_SetSleepMode(Afec *pAFE, uint8_t bEnDis)
184{
185        if (bEnDis)
186                pAFE->AFEC_MR |=  AFEC_MR_SLEEP;
187        else
188                pAFE->AFEC_MR &= ~AFEC_MR_SLEEP;
189}
190
191/**
192 * \brief Enable/Disable fast wake up.
193 *
194 * \param pAFE Pointer to an AFE instance.
195 * \param bEnDis Enable/Disable fast wake up in sleep mode.
196 */
197extern void AFEC_SetFastWakeup(Afec *pAFE, uint8_t bEnDis)
198{
199        if (bEnDis)
200                pAFE->AFEC_MR |=  AFEC_MR_FWUP;
201        else
202                pAFE->AFEC_MR &= ~AFEC_MR_FWUP;
203}
204
205/**
206 * \brief Enable/Disable sequence mode.
207 *
208 * \param pAFE  Pointer to an AFE instance.
209 * \param bEnDis Enable/Disable sequence mode.
210 */
211extern void AFEC_SetSequenceMode(Afec *pAFE, uint8_t bEnDis)
212{
213        if (bEnDis) {
214                /* User Sequence Mode: The sequence respects what is defined in
215                   AFEC_SEQR1 and AFEC_SEQR2 */
216                pAFE->AFEC_MR |=  AFEC_MR_USEQ;
217        } else {
218                /* Normal Mode: The controller converts channels in a simple
219                numeric order. */
220                pAFE->AFEC_MR &= ~AFEC_MR_USEQ;
221        }
222}
223
224/**
225 * \brief Set channel sequence.
226 *
227 * \param pAFE   Pointer to an AFE instance.
228 * \param dwSEQ1 Sequence 1 ~ 8  channel number.
229 * \param dwSEQ2 Sequence 9 ~ 16 channel number.
230 */
231extern void AFEC_SetSequence(Afec *pAFE, uint32_t dwSEQ1, uint32_t dwSEQ2)
232{
233        pAFE->AFEC_SEQ1R = dwSEQ1;
234        pAFE->AFEC_SEQ2R = dwSEQ2;
235}
236
237/**
238 * \brief Set channel sequence by given channel list.
239 *
240 * \param pAFE    Pointer to an AFE instance.
241 * \param ucChList Channel list.
242 * \param ucNumCh  Number of channels in list.
243 */
244extern void AFEC_SetSequenceByList(Afec *pAFE, uint8_t ucChList[],
245                                                                        uint8_t ucNumCh)
246{
247        uint8_t i;
248        uint8_t ucShift;
249
250        pAFE->AFEC_SEQ1R = 0;
251
252        for (i = 0, ucShift = 0; i < 8; i ++, ucShift += 4) {
253                if (i >= ucNumCh) return;
254
255                pAFE->AFEC_SEQ1R |= ucChList[i] << ucShift;
256
257        }
258
259        pAFE->AFEC_SEQ2R = 0;
260
261        for (ucShift = 0; i < 16; i ++, ucShift += 4) {
262                if (i >= ucNumCh) return;
263
264                pAFE->AFEC_SEQ2R |= ucChList[i] << ucShift;
265        }
266}
267
268/**
269 * \brief Set analog change.
270 * IF enabled, it allows different analog settings for each channel,
271 * otherwise, DIFF0, GAIN0 and OFF0 are used for all channels.
272 *
273 * \param pAFE   Pointer to an AFE instance.
274 * \param bEnDis Enable/Disable.
275 */
276extern void AFEC_SetAnalogChange(Afec *pAFE, uint8_t bEnDis)
277{
278        if (bEnDis)
279                pAFE->AFEC_MR |=  AFEC_MR_ONE;
280        else
281                pAFE->AFEC_MR &= ~AFEC_MR_ONE;
282}
283
284/**
285 * \brief Set "TAG" mode, show channel number in last data or not.
286 *
287 * \param pAFE   Pointer to an AFE instance.
288 * \param bEnDis Enable/Disable TAG value.
289 */
290extern void AFEC_SetTagEnable(Afec *pAFE, uint8_t bEnDis)
291{
292        if (bEnDis)
293                pAFE->AFEC_EMR |=  AFEC_EMR_TAG;
294        else
295                pAFE->AFEC_EMR &= ~AFEC_EMR_TAG;
296}
297
298/**
299 * \brief Set compare channel.
300 *
301 * \param pAFE Pointer to an AFE instance.
302 * \param dwChannel channel number to be set,16 for all channels
303 */
304extern void AFEC_SetCompareChannel(Afec *pAFE, uint32_t dwChannel)
305{
306        assert(dwChannel <= 16);
307
308        if (dwChannel < 16) {
309                pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPALL);
310                pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPSEL_Msk);
311                pAFE->AFEC_EMR |= (dwChannel << AFEC_EMR_CMPSEL_Pos);
312        } else
313                pAFE->AFEC_EMR |= AFEC_EMR_CMPALL;
314}
315
316/**
317 * \brief Set compare mode.
318 *
319 * \param pAFE Pointer to an AFE instance.
320 * \param dwMode compare mode
321 */
322extern void AFEC_SetCompareMode(Afec *pAFE, uint32_t dwMode)
323{
324        pAFE->AFEC_EMR &= ~(AFEC_EMR_CMPMODE_Msk);
325        pAFE->AFEC_EMR |= (dwMode & AFEC_EMR_CMPMODE_Msk);
326}
327
328/**
329 * \brief Set comparison window.
330 *
331 * \param pAFE Pointer to an AFE instance.
332 * \param dwHi_Lo Comparison Window
333 */
334extern void AFEC_SetComparisonWindow(Afec *pAFE, uint32_t dwHi_Lo)
335{
336        pAFE->AFEC_CWR = dwHi_Lo;
337}
338
339/**
340 * \brief Return the Channel Converted Data
341 *
342 * \param pAFE Pointer to an AFE instance.
343 * \param dwChannel channel to get converted value
344 */
345extern uint32_t AFEC_GetConvertedData(Afec *pAFE, uint32_t dwChannel)
346{
347        uint32_t dwData = 0;
348        assert(dwChannel < 12);
349        pAFE->AFEC_CSELR = dwChannel;
350        dwData = pAFE->AFEC_CDR;
351
352        return dwData;
353}
354
355
356/**
357 * Sets the AFE startup time.
358 * \param pAFE  Pointer to an AFE instance.
359 * \param dwUs  Startup time in uS.
360 */
361void AFEC_SetStartupTime(Afec *pAFE, uint32_t dwUs)
362{
363        uint32_t dwStart;
364        uint32_t dwMr;
365
366        if (dwAFEClock == 0) return;
367
368        /* Formula for STARTUP is:
369           STARTUP = (time x AFECLK) / (1000000) - 1
370           Division multiplied by 10 for higher precision */
371
372        dwStart = (dwUs * dwAFEClock) / (100000);
373
374        if (dwStart % 10) dwStart /= 10;
375        else {
376                dwStart /= 10;
377
378                if (dwStart) dwStart --;
379        }
380
381        if      (dwStart >  896) dwMr = AFEC_MR_STARTUP_SUT960;
382        else if (dwStart >  832) dwMr = AFEC_MR_STARTUP_SUT896;
383        else if (dwStart >  768) dwMr = AFEC_MR_STARTUP_SUT832;
384        else if (dwStart >  704) dwMr = AFEC_MR_STARTUP_SUT768;
385        else if (dwStart >  640) dwMr = AFEC_MR_STARTUP_SUT704;
386        else if (dwStart >  576) dwMr = AFEC_MR_STARTUP_SUT640;
387        else if (dwStart >  512) dwMr = AFEC_MR_STARTUP_SUT576;
388        else if (dwStart >  112) dwMr = AFEC_MR_STARTUP_SUT512;
389        else if (dwStart >   96) dwMr = AFEC_MR_STARTUP_SUT112;
390        else if (dwStart >   80) dwMr = AFEC_MR_STARTUP_SUT96;
391        else if (dwStart >   64) dwMr = AFEC_MR_STARTUP_SUT80;
392        else if (dwStart >   24) dwMr = AFEC_MR_STARTUP_SUT64;
393        else if (dwStart >   16) dwMr = AFEC_MR_STARTUP_SUT24;
394        else if (dwStart >    8) dwMr = AFEC_MR_STARTUP_SUT16;
395        else if (dwStart >    0) dwMr = AFEC_MR_STARTUP_SUT8;
396        else                     dwMr = AFEC_MR_STARTUP_SUT0;
397
398        dwMr |= pAFE->AFEC_MR & ~AFEC_MR_STARTUP_Msk;
399        pAFE->AFEC_MR = dwMr;
400}
401
402
403/**
404 * Set AFE tracking time
405 * \param pAFE  Pointer to an AFE instance.
406 * \param dwNs  Tracking time in nS.
407 */
408void AFEC_SetTrackingTime(Afec *pAFE, uint32_t dwNs)
409{
410        uint32_t dwShtim;
411        uint32_t dwMr;
412
413        if (dwAFEClock == 0) return;
414
415        /* Formula for SHTIM is:
416           SHTIM = (time x AFECLK) / (1000000000) - 1
417           Since 1 billion is close to the maximum value for an integer, we first
418           divide AFECLK by 1000 to avoid an overflow */
419        dwShtim = (dwNs * (dwAFEClock / 1000)) / 100000;
420
421        if (dwShtim % 10) dwShtim /= 10;
422        else {
423                dwShtim /= 10;
424
425                if (dwShtim) dwShtim --;
426        }
427
428        dwMr  = AFEC_MR_TRACKTIM(dwShtim);
429        dwMr |= pAFE->AFEC_MR & ~AFEC_MR_TRACKTIM_Msk;
430        pAFE->AFEC_MR = dwMr;
431}
432
433/**
434 * \brief Set analog offset to be used for channel CSEL.
435 *
436 * \param afec  Base address of the AFEC.
437 * \param dwChannel AFEC channel number.
438 * \param aoffset  Analog offset value.
439 */
440void AFEC_SetAnalogOffset(Afec *pAFE, uint32_t dwChannel, uint32_t aoffset)
441{
442        assert(dwChannel < 12);
443        pAFE->AFEC_CSELR = dwChannel;
444        pAFE->AFEC_COCR = (aoffset & AFEC_COCR_AOFF_Msk);;
445}
446
447/**
448 * \brief Set analog offset to be used for channel CSEL.
449 *
450 * \param afec  Base address of the AFEC.
451 * \param control  Analog control value.
452 */
453void AFEC_SetAnalogControl(Afec *pAFE, uint32_t control)
454{
455        pAFE->AFEC_ACR = control;
456}
457
458
Note: See TracBrowser for help on using the repository browser.