1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
/**************************************************************************//**
* @file eadc.c
* @version V2.00
* @brief EADC driver source file
*
* SPDX-License-Identifier: Apache-2.0
* @copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "NuMicro.h"
/** @addtogroup Standard_Driver Standard Driver
@{
*/
/** @addtogroup EADC_Driver EADC Driver
@{
*/
/** @addtogroup EADC_EXPORTED_FUNCTIONS EADC Exported Functions
@{
*/
int32_t g_EADC_i32ErrCode = 0; /*!< EADC global error code */
/**
* @brief This function make EADC_module be ready to convert.
* @param[in] eadc The pointer of the specified EADC module.
* @param[in] u32InputMode Decides the input mode.
* - \ref EADC_CTL_DIFFEN_SINGLE_END :Single end input mode.
* - \ref EADC_CTL_DIFFEN_DIFFERENTIAL :Differential input type.
* @return None
* @details This function is used to set analog input mode and enable A/D Converter.
* Before starting A/D conversion function, ADCEN bit (EADC_CTL[0]) should be set to 1.
* @note This API will reset and calibrate EADC if EADC never be calibrated after chip power on.
* @note This function sets g_EADC_i32ErrCode to EADC_TIMEOUT_ERR if CALIF(CALSR[16]) is not set to 1.
*/
void EADC_Open(EADC_T *eadc, uint32_t u32InputMode)
{
uint32_t u32Delay = SystemCoreClock >> 4;
uint32_t u32ClkSel0Backup, u32EadcDivBackup, u32PclkDivBackup, u32RegLockBackup = 0;
g_EADC_i32ErrCode = 0;
eadc->CTL &= (~EADC_CTL_DIFFEN_Msk);
eadc->CTL |= (u32InputMode | EADC_CTL_ADCEN_Msk);
/* Do calibration for EADC to decrease the effect of electrical random noise. */
if ((eadc->CALSR & EADC_CALSR_CALIF_Msk) == 0)
{
/* Must reset ADC before ADC calibration */
eadc->CTL |= EADC_CTL_ADCRST_Msk;
while ((eadc->CTL & EADC_CTL_ADCRST_Msk) == EADC_CTL_ADCRST_Msk)
{
if (--u32Delay == 0)
{
g_EADC_i32ErrCode = EADC_TIMEOUT_ERR;
break;
}
}
/* Registers backup */
u32ClkSel0Backup = CLK->CLKSEL0;
u32PclkDivBackup = CLK->PCLKDIV;
u32RegLockBackup = SYS_IsRegLocked();
/* Unlock protected registers */
SYS_UnlockReg();
/* Set PCLK and EADC clock to the same frequency. */
if (eadc == EADC0)
{
u32EadcDivBackup = CLK->CLKDIV0;
CLK->CLKDIV0 = (CLK->CLKDIV0 & ~CLK_CLKDIV0_EADC0DIV_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_EADC0SEL_Msk) | CLK_CLKSEL0_EADC0SEL_HCLK;
}
else if (eadc == EADC1)
{
u32EadcDivBackup = CLK->CLKDIV2;
CLK->CLKDIV2 = (CLK->CLKDIV2 & ~CLK_CLKDIV2_EADC1DIV_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_EADC1SEL_Msk) | CLK_CLKSEL0_EADC1SEL_HCLK;
}
else if (eadc == EADC2)
{
u32EadcDivBackup = CLK->CLKDIV5;
CLK->CLKDIV5 = (CLK->CLKDIV5 & ~CLK_CLKDIV5_EADC2DIV_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_EADC2SEL_Msk) | CLK_CLKSEL0_EADC2SEL_HCLK;
}
CLK->PCLKDIV = (CLK->PCLKDIV & ~CLK_PCLKDIV_APB1DIV_Msk);
eadc->CALSR |= EADC_CALSR_CALIF_Msk; /* Clear Calibration Finish Interrupt Flag */
eadc->CALCTL = (eadc->CALCTL & ~(0x000F0000)) | 0x00020000;
eadc->CALCTL |= EADC_CALCTL_CAL_Msk; /* Enable Calibration function */
u32Delay = SystemCoreClock >> 4;
while ((eadc->CALSR & EADC_CALSR_CALIF_Msk) != EADC_CALSR_CALIF_Msk)
{
if (--u32Delay == 0)
{
g_EADC_i32ErrCode = EADC_TIMEOUT_ERR;
break;
}
}
/* Restore registers */
CLK->PCLKDIV = (CLK->PCLKDIV & ~CLK_PCLKDIV_APB1DIV_Msk) | (u32PclkDivBackup & CLK_PCLKDIV_APB1DIV_Msk);
if (eadc == EADC0)
{
CLK->CLKDIV0 = (u32EadcDivBackup & CLK_CLKDIV0_EADC0DIV_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_EADC0SEL_Msk) | (u32ClkSel0Backup & CLK_CLKSEL0_EADC0SEL_Msk);
}
else if (eadc == EADC1)
{
CLK->CLKDIV2 = (u32EadcDivBackup & CLK_CLKDIV2_EADC1DIV_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_EADC1SEL_Msk) | (u32ClkSel0Backup & CLK_CLKSEL0_EADC1SEL_Msk);
}
else if (eadc == EADC2)
{
CLK->CLKDIV5 = (u32EadcDivBackup & CLK_CLKDIV5_EADC2DIV_Msk);
CLK->CLKSEL0 = (CLK->CLKSEL0 & ~CLK_CLKSEL0_EADC2SEL_Msk) | (u32ClkSel0Backup & CLK_CLKSEL0_EADC2SEL_Msk);
}
if (u32RegLockBackup)
{
/* Lock protected registers */
SYS_LockReg();
}
}
}
/**
* @brief Disable EADC_module.
* @param[in] eadc The pointer of the specified EADC module.
* @return None
* @details Clear ADCEN bit (EADC_CTL[0]) to disable A/D converter analog circuit power consumption.
*/
void EADC_Close(EADC_T *eadc)
{
eadc->CTL &= ~EADC_CTL_ADCEN_Msk;
}
/**
* @brief Configure the sample control logic module.
* @param[in] eadc The pointer of the specified EADC module.
* @param[in] u32ModuleNum Decides the sample module number, valid value are from 0 to 15.
* @param[in] u32TriggerSrc Decides the trigger source. Valid values are:
* - \ref EADC_SOFTWARE_TRIGGER : Disable trigger
* - \ref EADC_FALLING_EDGE_TRIGGER : STADC pin falling edge trigger
* - \ref EADC_RISING_EDGE_TRIGGER : STADC pin rising edge trigger
* - \ref EADC_FALLING_RISING_EDGE_TRIGGER : STADC pin both falling and rising edge trigger
* - \ref EADC_ADINT0_TRIGGER : EADC ADINT0 interrupt EOC pulse trigger
* - \ref EADC_ADINT1_TRIGGER : EADC ADINT1 interrupt EOC pulse trigger
* - \ref EADC_TIMER0_TRIGGER : Timer0 overflow pulse trigger
* - \ref EADC_TIMER1_TRIGGER : Timer1 overflow pulse trigger
* - \ref EADC_TIMER2_TRIGGER : Timer2 overflow pulse trigger
* - \ref EADC_TIMER3_TRIGGER : Timer3 overflow pulse trigger
* - \ref EADC_EPWM0TG0_TRIGGER : EPWM0TG0 trigger
* - \ref EADC_EPWM0TG1_TRIGGER : EPWM0TG1 trigger
* - \ref EADC_EPWM0TG2_TRIGGER : EPWM0TG2 trigger
* - \ref EADC_EPWM0TG3_TRIGGER : EPWM0TG3 trigger
* - \ref EADC_EPWM0TG4_TRIGGER : EPWM0TG4 trigger
* - \ref EADC_EPWM0TG5_TRIGGER : EPWM0TG5 trigger
* - \ref EADC_EPWM1TG0_TRIGGER : EPWM1TG0 trigger
* - \ref EADC_EPWM1TG1_TRIGGER : EPWM1TG1 trigger
* - \ref EADC_EPWM1TG2_TRIGGER : EPWM1TG2 trigger
* - \ref EADC_EPWM1TG3_TRIGGER : EPWM1TG3 trigger
* - \ref EADC_EPWM1TG4_TRIGGER : EPWM1TG4 trigger
* - \ref EADC_EPWM1TG5_TRIGGER : EPWM1TG5 trigger
* - \ref EADC_BPWM0TG_TRIGGER : BPWM0TG trigger
* - \ref EADC_BPWM1TG_TRIGGER : BPWM1TG trigger
* @param[in] u32Channel Specifies the sample module channel, valid value are from 0 to 15.
* @return None
* @details Each of ADC control logic modules 0~15 which is configurable for ADC converter channel EADC_CH0~15 and trigger source.
* sample module 16~18 is fixed for ADC channel 16, 17, 18 input sources as band-gap voltage, temperature sensor, and battery power (VBAT).
*/
void EADC_ConfigSampleModule(EADC_T *eadc, \
uint32_t u32ModuleNum, \
uint32_t u32TriggerSrc, \
uint32_t u32Channel)
{
eadc->SCTL[u32ModuleNum] &= ~(EADC_SCTL_EXTFEN_Msk | EADC_SCTL_EXTREN_Msk | EADC_SCTL_TRGSEL_Msk | EADC_SCTL_CHSEL_Msk);
eadc->SCTL[u32ModuleNum] |= (u32TriggerSrc | u32Channel);
}
/**
* @brief Set trigger delay time.
* @param[in] eadc The pointer of the specified EADC module.
* @param[in] u32ModuleNum Decides the sample module number, valid value are from 0 to 15.
* @param[in] u32TriggerDelayTime Decides the trigger delay time, valid range are between 0~0xFF.
* @param[in] u32DelayClockDivider Decides the trigger delay clock divider. Valid values are:
* - \ref EADC_SCTL_TRGDLYDIV_DIVIDER_1 : Trigger delay clock frequency is ADC_CLK/1
* - \ref EADC_SCTL_TRGDLYDIV_DIVIDER_2 : Trigger delay clock frequency is ADC_CLK/2
* - \ref EADC_SCTL_TRGDLYDIV_DIVIDER_4 : Trigger delay clock frequency is ADC_CLK/4
* - \ref EADC_SCTL_TRGDLYDIV_DIVIDER_16 : Trigger delay clock frequency is ADC_CLK/16
* @return None
* @details User can configure the trigger delay time by setting TRGDLYCNT (EADC_SCTLn[15:8], n=0~15) and TRGDLYDIV (EADC_SCTLn[7:6], n=0~15).
* Trigger delay time = (u32TriggerDelayTime) x Trigger delay clock period.
*/
void EADC_SetTriggerDelayTime(EADC_T *eadc, \
uint32_t u32ModuleNum, \
uint32_t u32TriggerDelayTime, \
uint32_t u32DelayClockDivider)
{
eadc->SCTL[u32ModuleNum] &= ~(EADC_SCTL_TRGDLYDIV_Msk | EADC_SCTL_TRGDLYCNT_Msk);
eadc->SCTL[u32ModuleNum] |= ((u32TriggerDelayTime << EADC_SCTL_TRGDLYCNT_Pos) | u32DelayClockDivider);
}
/**
* @brief Set ADC extend sample time.
* @param[in] eadc The pointer of the specified EADC module.
* @param[in] u32ModuleNum Decides the sample module number, valid value are from 0 to 18.
* @param[in] u32ExtendSampleTime Decides the extend sampling time, the range is from 0~255 ADC clock. Valid value are from 0 to 0xFF.
* @return None
* @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,
* user can extend A/D sampling time after trigger source is coming to get enough sampling time.
*/
void EADC_SetExtendSampleTime(EADC_T *eadc, uint32_t u32ModuleNum, uint32_t u32ExtendSampleTime)
{
eadc->SCTL[u32ModuleNum] &= ~EADC_SCTL_EXTSMPT_Msk;
eadc->SCTL[u32ModuleNum] |= (u32ExtendSampleTime << EADC_SCTL_EXTSMPT_Pos);
}
/*@}*/ /* end of group EADC_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group EADC_Driver */
/*@}*/ /* end of group Standard_Driver */
|