1 /**************************************************************************//**
2  * @file     lpadc.c
3  * @version  V1.00
4  * @brief    M2L31 series LPADC driver source file
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  * Copyright (C) 2023 Nuvoton Technology Corp. All rights reserved.
8  *****************************************************************************/
9 #include "NuMicro.h"
10 
11 /** @addtogroup Standard_Driver Standard Driver
12   @{
13 */
14 
15 /** @addtogroup LPADC_Driver LPADC Driver
16   @{
17 */
18 
19 int32_t g_LPADC_i32ErrCode = 0;   /*!< LPADC global error code */
20 
21 /** @addtogroup LPADC_EXPORTED_FUNCTIONS LPADC Exported Functions
22   @{
23 */
24 
25 /**
26   * @brief This API configures LPADC module to be ready for convert the input from selected channel
27   * @param[in] lpadc The pointer of the specified LPADC module
28   * @param[in] u32InputMode Decides the LPADC analog input mode. Valid values are:
29   *                          - \ref LPADC_ADCR_DIFFEN_SINGLE_END      :Single-end input mode
30   *                          - \ref LPADC_ADCR_DIFFEN_DIFFERENTIAL    :Differential input mode
31   * @param[in] u32OpMode Decides the LPADC operation mode. Valid values are:
32   *                       - \ref LPADC_ADCR_ADMD_SINGLE               :Single mode.
33   *                       - \ref LPADC_ADCR_ADMD_BURST                :Burst mode.
34   *                       - \ref LPADC_ADCR_ADMD_SINGLE_CYCLE         :Single cycle scan mode.
35   *                       - \ref LPADC_ADCR_ADMD_CONTINUOUS           :Continuous scan mode.
36   * @param[in] u32ChMask Channel enable bit. Each bit corresponds to a input channel. Bit 0 is channel 0, bit 1 is channel 1..., bit 15 is channel 15.
37   * @return  None
38   * @note LPADC can only convert 1 channel at a time. If more than 1 channels are enabled, only channel
39   *       with smallest number will be convert.
40   * @note This API does not turn on LPADC power nor does trigger LPADC conversion.
41   * @note This API will reset and calibrate LPADC if LPADC never be calibrated after chip power on.
42   * @note This function sets g_LPADC_i32ErrCode to LPADC_TIMEOUT_ERR if CALIF(LPADC_ADCALSTSR[0]) is not set to 1
43   */
LPADC_Open(LPADC_T * lpadc,uint32_t u32InputMode,uint32_t u32OpMode,uint32_t u32ChMask)44 void LPADC_Open(LPADC_T *lpadc,
45                 uint32_t u32InputMode,
46                 uint32_t u32OpMode,
47                 uint32_t u32ChMask)
48 {
49     uint32_t u32Delay = SystemCoreClock;    /* 1 second */
50 
51     /* select LPADC0 as LPADC controller, not EADC0. */
52     SYS->IVSCTL |= SYS_IVSCTL_ADCCSEL_Msk;
53 
54     g_LPADC_i32ErrCode = 0;
55 
56     /*Wait the LPADC Power On Ready  */
57     while (!(lpadc->ADSR0 & LPADC_ADSR0_ADPRDY_Msk))
58     {
59         if (--u32Delay == 0)
60         {
61             g_LPADC_i32ErrCode = LPADC_TIMEOUT_ERR;
62             break;
63         }
64     }
65 
66     /* Do calibration for LPADC to decrease the effect of electrical random noise. */
67     if ((lpadc->ADCALSTS & LPADC_ADCALSTS_CALIF_Msk) == 0)
68     {
69         /* Must reset LPADC before LPADC calibration */
70         lpadc->ADCR |= LPADC_ADCR_RESET_Msk;
71         while((lpadc->ADCR & LPADC_ADCR_RESET_Msk) == LPADC_ADCR_RESET_Msk)
72         {
73             if (--u32Delay == 0)
74             {
75                 g_LPADC_i32ErrCode = LPADC_TIMEOUT_ERR;
76                 break;
77             }
78         }
79 
80         lpadc->ADCALSTS |= LPADC_ADCALSTS_CALIF_Msk;    /* Clear Calibration Finish Interrupt Flag */
81         lpadc->ADCAL |= LPADC_ADCAL_CALEN_Msk;          /* Enable Calibration function */
82         LPADC_START_CONV(lpadc);                        /* Start to calibration */
83         u32Delay = SystemCoreClock;
84         while((lpadc->ADCALSTS & LPADC_ADCALSTS_CALIF_Msk) != LPADC_ADCALSTS_CALIF_Msk) /* Wait calibration finish */
85         {
86             if (--u32Delay == 0)
87             {
88                 g_LPADC_i32ErrCode = LPADC_TIMEOUT_ERR;
89                 break;
90             }
91         }
92     }
93 
94     lpadc->ADCR = (lpadc->ADCR & (~(LPADC_ADCR_DIFFEN_Msk | LPADC_ADCR_ADMD_Msk))) |
95                   (u32InputMode) | (u32OpMode);
96 
97     lpadc->ADCHER = (lpadc->ADCHER & ~LPADC_ADCHER_CHEN_Msk) | (u32ChMask);
98 
99     return;
100 }
101 
102 /**
103   * @brief Disable LPADC module
104   * @param[in] lpadc The pointer of the specified LPADC module
105   * @return None
106   */
LPADC_Close(LPADC_T * lpadc)107 void LPADC_Close(LPADC_T *lpadc)
108 {
109     SYS_UnlockReg();
110     LPSCC->IPRST0 |= (LPSCC_IPRST0_LPADC0RST_Msk);
111     LPSCC->IPRST0 &= ~(LPSCC_IPRST0_LPADC0RST_Msk);
112     SYS_LockReg();
113     return;
114 }
115 
116 /**
117   * @brief Configure the hardware trigger condition and enable hardware trigger
118   * @param[in] lpadc The pointer of the specified LPADC module
119   * @param[in] u32Source Decides the hardware trigger source. Valid values are:
120   *                       - \ref LPADC_ADCR_TRGS_STADC  :A/D conversion is started by external STADC pin.
121   *                       - \ref LPADC_ADCR_TRGS_TIMER  :A/D conversion is started by Timer.
122   *                       - \ref LPADC_ADCR_TRGS_PWM    :A/D conversion is started by PWM.
123   *                       - \ref LPADC_ADCR_TRGS_EPWM   :A/D conversion is started by EPWM.
124   *                       - \ref LPADC_ADCR_TRGS_ACMP0  :A/D conversion is started by ACMP0.
125   *                       - \ref LPADC_ADCR_TRGS_ACMP1  :A/D conversion is started by ACMP1.
126   *                       - \ref LPADC_ADCR_TRGS_ACMP2  :A/D conversion is started by ACMP2.
127   * @param[in] u32Param While LPADC trigger by external pin, this parameter is used to set trigger condition.
128   *                     Valid values are:
129   *                      - \ref LPADC_ADCR_TRGCOND_LOW_LEVEL     :STADC Low level active
130   *                      - \ref LPADC_ADCR_TRGCOND_HIGH_LEVEL    :STADC High level active
131   *                      - \ref LPADC_ADCR_TRGCOND_FALLING_EDGE  :STADC Falling edge active
132   *                      - \ref LPADC_ADCR_TRGCOND_RISING_EDGE   :STADC Rising edge active
133   *                     While LPADC trigger by other source, this parameter is unused.
134   * @return None
135   * @note Software should disable TRGEN and ADST before change TRGS.
136   */
LPADC_EnableHWTrigger(LPADC_T * lpadc,uint32_t u32Source,uint32_t u32Param)137 void LPADC_EnableHWTrigger(LPADC_T *lpadc,
138                            uint32_t u32Source,
139                            uint32_t u32Param)
140 {
141     /* Software should clear TRGEN bit and ADST bit before changing TRGS bits. */
142     lpadc->ADCR &= ~(LPADC_ADCR_TRGEN_Msk | LPADC_ADCR_ADST_Msk);
143 
144     if(u32Source == LPADC_ADCR_TRGS_STADC)
145     {
146         lpadc->ADCR = (lpadc->ADCR & ~(LPADC_ADCR_TRGS_Msk | LPADC_ADCR_TRGCOND_Msk)) |
147                       ((u32Source) | (u32Param) | LPADC_ADCR_TRGEN_Msk);
148     }
149     else
150     {
151         lpadc->ADCR = (lpadc->ADCR & ~(LPADC_ADCR_TRGS_Msk | LPADC_ADCR_TRGCOND_Msk)) |
152                       ((u32Source) | LPADC_ADCR_TRGEN_Msk);
153     }
154     return;
155 }
156 
157 /**
158   * @brief Disable hardware trigger LPADC function.
159   * @param[in] lpadc The pointer of the specified LPADC module
160   * @return None
161   */
LPADC_DisableHWTrigger(LPADC_T * lpadc)162 void LPADC_DisableHWTrigger(LPADC_T *lpadc)
163 {
164     /* Software should clear TRGEN bit and ADST bit before changing TRGS bits. */
165     lpadc->ADCR &= ~(LPADC_ADCR_TRGEN_Msk | LPADC_ADCR_ADST_Msk);
166     lpadc->ADCR &= ~(LPADC_ADCR_TRGS_Msk | LPADC_ADCR_TRGCOND_Msk);
167     return;
168 }
169 
170 /**
171   * @brief Enable the interrupt(s) selected by u32Mask parameter.
172   * @param[in] lpadc The pointer of the specified LPADC module
173   * @param[in] u32Mask The combination of interrupt status bits listed below. Each bit
174   *                    corresponds to a interrupt status. This parameter decides which
175   *                    interrupts will be enabled.
176   *                     - \ref LPADC_ADF_INT    :LPADC convert complete interrupt
177   *                     - \ref LPADC_CMP0_INT   :LPADC comparator 0 interrupt
178   *                     - \ref LPADC_CMP1_INT   :LPADC comparator 1 interrupt
179   * @return None
180   */
LPADC_EnableInt(LPADC_T * lpadc,uint32_t u32Mask)181 void LPADC_EnableInt(LPADC_T *lpadc, uint32_t u32Mask)
182 {
183     if((u32Mask) & LPADC_ADF_INT)
184         lpadc->ADCR |= LPADC_ADCR_ADIE_Msk;
185     if((u32Mask) & LPADC_CMP0_INT)
186         lpadc->ADCMPR[0] |= LPADC_ADCMPR_CMPIE_Msk;
187     if((u32Mask) & LPADC_CMP1_INT)
188         lpadc->ADCMPR[1] |= LPADC_ADCMPR_CMPIE_Msk;
189 
190     return;
191 }
192 
193 /**
194   * @brief Disable the interrupt(s) selected by u32Mask parameter.
195   * @param[in] lpadc The pointer of the specified LPADC module
196   * @param[in] u32Mask The combination of interrupt status bits listed below. Each bit
197   *                    corresponds to a interrupt status. This parameter decides which
198   *                    interrupts will be disabled.
199   *                     - \ref LPADC_ADF_INT     :LPADC convert complete interrupt
200   *                     - \ref LPADC_CMP0_INT    :LPADC comparator 0 interrupt
201   *                     - \ref LPADC_CMP1_INT    :LPADC comparator 1 interrupt
202   * @return None
203   */
LPADC_DisableInt(LPADC_T * lpadc,uint32_t u32Mask)204 void LPADC_DisableInt(LPADC_T *lpadc, uint32_t u32Mask)
205 {
206     if((u32Mask) & LPADC_ADF_INT)
207         lpadc->ADCR &= ~LPADC_ADCR_ADIE_Msk;
208     if((u32Mask) & LPADC_CMP0_INT)
209         lpadc->ADCMPR[0] &= ~LPADC_ADCMPR_CMPIE_Msk;
210     if((u32Mask) & LPADC_CMP1_INT)
211         lpadc->ADCMPR[1] &= ~LPADC_ADCMPR_CMPIE_Msk;
212 
213     return;
214 }
215 
216 /**
217   * @brief Set LPADC extend sample time.
218   * @param[in] lpadc The pointer of the specified LPADC module.
219   * @param[in] u32ModuleNum Decides the sample module number, valid value are 0.
220   * @param[in] u32ExtendSampleTime Decides the extend sampling time, the range is from 0~255 LPADC clock. Valid value are from 0 to 0xFF.
221   * @return None
222   * @details When A/D converting at high conversion rate, the sampling time of analog input voltage may not enough if input channel loading is heavy,
223   *         user can extend A/D sampling time after trigger source is coming to get enough sampling time.
224   */
LPADC_SetExtendSampleTime(LPADC_T * lpadc,uint32_t u32ModuleNum,uint32_t u32ExtendSampleTime)225 void LPADC_SetExtendSampleTime(LPADC_T *lpadc, uint32_t u32ModuleNum, uint32_t u32ExtendSampleTime)
226 {
227     lpadc->ESMPCTL = (lpadc->ESMPCTL & ~LPADC_ESMPCTL_EXTSMPT_Msk) |
228                      (u32ExtendSampleTime << LPADC_ESMPCTL_EXTSMPT_Pos);
229 }
230 
231 /**
232   * @brief  Select and configure Automatic Operation function
233   * @param[in] lpadc The pointer of the specified LPADC module
234   * @param[in] u32TrigSel  The LPADC Automatic Operation Trigger Source:
235   *                       - \ref LPADC_AUTOCTL_TRIGSEL_SOFTWARE : Auto-operation Trigger Source from Software .
236   *                       - \ref LPADC_AUTOCTL_TRIGSEL_LPTMR0   : Auto-operation Trigger Source from LPTMR0.
237   *                       - \ref LPADC_AUTOCTL_TRIGSEL_LPTMR1   : Auto-operation Trigger Source from LPTMR1.
238   *                       - \ref LPADC_AUTOCTL_TRIGSEL_TTMR0    : Auto-operation Trigger Source from TTMR0.
239   *                       - \ref LPADC_AUTOCTL_TRIGSEL_TTMR1    : Auto-operation Trigger Source from TTMR1.
240   *                       - \ref LPADC_AUTOCTL_TRIGSEL_WKIOA0   : Auto-operation Trigger Source from WKIOA0.
241   *                       - \ref LPADC_AUTOCTL_TRIGSEL_WKIOB0   : Auto-operation Trigger Source from WKIOB0.
242   *                       - \ref LPADC_AUTOCTL_TRIGSEL_WKIOC0   : Auto-operation Trigger Source from WKIOC0.
243   *                       - \ref LPADC_AUTOCTL_TRIGSEL_WKIOD0   : Auto-operation Trigger Source from WKIOD0.
244   *                       - \ref LPADC_AUTOCTL_TRIGSEL_ACMP0    : Auto-operation Trigger Source from ACMP0.
245   *                       - \ref LPADC_AUTOCTL_TRIGSEL_ACMP1    : Auto-operation Trigger Source from ACMP1.
246   *                       - \ref LPADC_AUTOCTL_TRIGSEL_ACMP2    : Auto-operation Trigger Source from ACMP2.
247   * @return  None
248   * @details The function is used to set Automatic Operation relative setting.
249   */
LPADC_SelectAutoOperationMode(LPADC_T * lpadc,uint32_t u32TrigSel)250 void LPADC_SelectAutoOperationMode(LPADC_T *lpadc, uint32_t u32TrigSel)
251 {
252     /* Automatic Operation Mode Disable */
253     lpadc->AUTOCTL &= ~(LPADC_AUTOCTL_AUTOEN_Msk);
254 
255     if (u32TrigSel == LPADC_AUTOCTL_TRIGSEL_SOFTWARE)
256         lpadc->AUTOCTL = (lpadc->AUTOCTL & ~(LPADC_AUTOCTL_TRIGSEL_Msk | LPADC_AUTOCTL_TRIGEN_Msk));
257     else
258         lpadc->AUTOCTL = (lpadc->AUTOCTL & ~(LPADC_AUTOCTL_TRIGSEL_Msk | LPADC_AUTOCTL_TRIGEN_Msk)) |
259                          (u32TrigSel | LPADC_AUTOCTL_TRIGEN_Msk);
260 
261     /* Automatic Operation Mode Enable */
262     lpadc->AUTOCTL |= LPADC_AUTOCTL_AUTOEN_Msk;
263 }
264 
265 /*@}*/ /* end of group LPADC_EXPORTED_FUNCTIONS */
266 
267 /*@}*/ /* end of group LPADC_Driver */
268 
269 /*@}*/ /* end of group Standard_Driver */
270 
271 /*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/
272