1 /******************************************************************************************************************************************
2 * 文件名称: SWM341_adc.c
3 * 功能说明: SWM341单片机的ADC数模转换器功能驱动库
4 * 技术支持: http://www.synwit.com.cn/e/tool/gbook/?bid=1
5 * 注意事项:
6 * 版本日期: V1.0.0      2016年1月30日
7 * 升级记录:
8 *******************************************************************************************************************************************
9 * @attention
10 *
11 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS WITH CODING INFORMATION
12 * REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. AS A RESULT, SYNWIT SHALL NOT BE HELD LIABLE
13 * FOR ANY DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
14 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION CONTAINED HEREIN IN CONN-
15 * -ECTION WITH THEIR PRODUCTS.
16 *
17 * COPYRIGHT 2012 Synwit Technology
18 *******************************************************************************************************************************************/
19 #include "SWM341.h"
20 #include "SWM341_adc.h"
21 
22 
23 /******************************************************************************************************************************************
24 * 函数名称: ADC_Init()
25 * 功能说明: ADC模数转换器初始化
26 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
27 *           ADC_InitStructure * initStruct      包含ADC各相关定值的结构体
28 * 输    出: 无
29 * 注意事项: 无
30 ******************************************************************************************************************************************/
ADC_Init(ADC_TypeDef * ADCx,ADC_InitStructure * initStruct)31 void ADC_Init(ADC_TypeDef * ADCx, ADC_InitStructure * initStruct)
32 {
33     uint32_t i;
34 
35     switch((uint32_t)ADCx)
36     {
37     case ((uint32_t)ADC0):
38         SYS->CLKSEL &= ~(SYS_CLKSEL_AD0_Msk | SYS_CLKSEL_AD0DIV_Msk);
39         SYS->CLKSEL |= (initStruct->clk_src << SYS_CLKSEL_AD0_Pos);
40 
41         SYS->CLKEN0 |= (0x01 << SYS_CLKEN0_ADC0_Pos);
42         break;
43 
44     case ((uint32_t)ADC1):
45         SYS->CLKSEL &= ~(SYS_CLKSEL_AD1_Msk | SYS_CLKSEL_AD1DIV_Msk);
46         SYS->CLKSEL |= (initStruct->clk_src << SYS_CLKSEL_AD1_Pos);
47 
48         SYS->CLKEN1 |= (0x01 << SYS_CLKEN1_ADC1_Pos);
49         break;
50     }
51 
52     ADC_Close(ADCx);        //一些关键寄存器只能在ADC关闭时设置
53 
54     ADCx->CR |= (1 <<ADC_CR_RESET_Pos);
55     for(i = 0; i < 120*20; i++) __NOP();    //至少2个采样时钟周期
56     ADCx->CR &= ~(1 << ADC_CR_RESET_Pos);
57 
58     ADCx->CR |= (0xF << ADC_CR_FFCLR_Pos);
59     ADCx->CR &= ~(0xF << ADC_CR_FFCLR_Pos);
60 
61     ADCx->CR &= ~ADC_CR_AVG_Msk;
62     ADCx->CR |= (initStruct->samplAvg << ADC_CR_AVG_Pos);
63 
64     ADCx->IE = 0;
65     ADCx->IF = 0x3F3F3F3F;  //清除中断标志
66 
67     ADCx->IE |= (((initStruct->EOC_IEn & ADC_SEQ0) ? 1 : 0) << ADC_IE_SEQ0EOC_Pos) |
68                 (((initStruct->EOC_IEn & ADC_SEQ1) ? 1 : 0) << ADC_IE_SEQ1EOC_Pos) |
69                 (((initStruct->EOC_IEn & ADC_SEQ2) ? 1 : 0) << ADC_IE_SEQ2EOC_Pos) |
70                 (((initStruct->EOC_IEn & ADC_SEQ3) ? 1 : 0) << ADC_IE_SEQ3EOC_Pos);
71 
72     ADCx->IE |= (((initStruct->HalfIEn & ADC_SEQ0) ? 1 : 0) << ADC_IE_SEQ0HALF_Pos) |
73                 (((initStruct->HalfIEn & ADC_SEQ1) ? 1 : 0) << ADC_IE_SEQ1HALF_Pos) |
74                 (((initStruct->HalfIEn & ADC_SEQ2) ? 1 : 0) << ADC_IE_SEQ2HALF_Pos) |
75                 (((initStruct->HalfIEn & ADC_SEQ3) ? 1 : 0) << ADC_IE_SEQ3HALF_Pos);
76 
77     switch((uint32_t)ADCx)
78     {
79     case ((uint32_t)ADC0):
80         if(initStruct->EOC_IEn | initStruct->HalfIEn) NVIC_EnableIRQ(ADC0_IRQn);
81         break;
82 
83     case ((uint32_t)ADC1):
84         if(initStruct->EOC_IEn | initStruct->HalfIEn) NVIC_EnableIRQ(ADC1_IRQn);
85         break;
86     }
87 }
88 
ADC_seq2pos(uint32_t seq)89 static uint32_t ADC_seq2pos(uint32_t seq)
90 {
91     uint32_t pos = 0;
92 
93     switch(seq)
94     {
95     case ADC_SEQ0: pos = 0;  break;
96     case ADC_SEQ1: pos = 8;  break;
97     case ADC_SEQ2: pos = 16; break;
98     case ADC_SEQ3: pos = 24; break;
99     }
100 
101     return pos;
102 }
103 
104 /******************************************************************************************************************************************
105 * 函数名称: ADC_SEQ_Init()
106 * 功能说明: ADC序列初始化
107 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
108 *           uint32_t seq            指定要设置的序列,有效值包括ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
109 *           ADC_SEQ_InitStructure * initStruct      包含ADC序列设定定值的结构体
110 * 输    出: 无
111 * 注意事项: 无
112 ******************************************************************************************************************************************/
ADC_SEQ_Init(ADC_TypeDef * ADCx,uint32_t seq,ADC_SEQ_InitStructure * initStruct)113 void ADC_SEQ_Init(ADC_TypeDef * ADCx, uint32_t seq, ADC_SEQ_InitStructure * initStruct)
114 {
115     uint32_t pos = ADC_seq2pos(seq);
116 
117     switch(seq)
118     {
119     case ADC_SEQ0:
120     case ADC_SEQ1:
121         ADCx->SEQCHN0 &= ~(0xFFFu              << (pos * 2));
122         ADCx->SEQCHN0 |= (initStruct->channels << (pos * 2));
123         break;
124 
125     case ADC_SEQ2:
126     case ADC_SEQ3:
127         ADCx->SEQCHN1 &= ~(0xFFFu              << ((pos - 16) * 2));
128         ADCx->SEQCHN1 |= (initStruct->channels << ((pos - 16) * 2));
129         break;
130     }
131 
132     ADCx->SEQTRG &= ~(0xFFu << pos);
133     ADCx->SEQTRG |= (initStruct->trig_src << pos);
134 
135     ADCx->SEQCOV &= ~(0xFFu << pos);
136     ADCx->SEQCOV |= ((initStruct->conv_cnt ? initStruct->conv_cnt - 1 : 0) << pos);
137 
138     ADCx->SEQSMP &= ~(0x0Fu << (pos >> 1));
139     ADCx->SEQSMP |= (initStruct->samp_tim << (pos >> 1));
140 }
141 
142 /******************************************************************************************************************************************
143 * 函数名称: ADC_CMP_Init()
144 * 功能说明: ADC比较功能初始化
145 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
146 *           uint32_t seq            指定要设置的序列,有效值包括ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
147 *           ADC_CMP_InitStructure * initStruct      包含ADC比较功能设定定值的结构体
148 * 输    出: 无
149 * 注意事项: 无
150 ******************************************************************************************************************************************/
ADC_CMP_Init(ADC_TypeDef * ADCx,uint32_t seq,ADC_CMP_InitStructure * initStruct)151 void ADC_CMP_Init(ADC_TypeDef * ADCx, uint32_t seq, ADC_CMP_InitStructure * initStruct)
152 {
153     uint32_t idx;
154     uint32_t pos = ADC_seq2pos(seq);
155 
156     idx = pos / 8;
157     ADCx->SEQ[idx].CMP = (initStruct->UpperLimit << ADC_CMP_MAX_Pos) |
158                          (initStruct->LowerLimit << ADC_CMP_MIN_Pos);
159 
160     if(initStruct->UpperLimitIEn) ADCx->IE |= (1 << (pos + 4));
161     else                          ADCx->IE &= ~(1 << (pos + 4));
162 
163     if(initStruct->LowerLimitIEn) ADCx->IE |= (1 << (pos + 5));
164     else                          ADCx->IE &= ~(1 << (pos + 5));
165 
166     if(initStruct->UpperLimitIEn || initStruct->LowerLimitIEn)
167     {
168         switch((uint32_t)ADCx)
169         {
170         case ((uint32_t)ADC0): NVIC_EnableIRQ(ADC0_IRQn); break;
171         case ((uint32_t)ADC1): NVIC_EnableIRQ(ADC1_IRQn); break;
172         }
173     }
174 }
175 
176 /******************************************************************************************************************************************
177 * 函数名称: ADC_Open()
178 * 功能说明: ADC开启,可以软件启动、或硬件触发ADC转换
179 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
180 * 输    出: 无
181 * 注意事项: 无
182 ******************************************************************************************************************************************/
ADC_Open(ADC_TypeDef * ADCx)183 void ADC_Open(ADC_TypeDef * ADCx)
184 {
185     uint32_t i;
186 
187     ADCx->CR2 |= (1 << ADC_CR2_ENLDO_Pos);
188     for(i = 0; i < 64*20; i++) __NOP();
189 
190     ADCx->CR |= (0x01 << ADC_CR_EN_Pos);
191 }
192 
193 /******************************************************************************************************************************************
194 * 函数名称: ADC_Calibrate()
195 * 功能说明: ADC校准
196 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
197 * 输    出: 无
198 * 注意事项: 无
199 ******************************************************************************************************************************************/
ADC_Calibrate(ADC_TypeDef * ADCx)200 void ADC_Calibrate(ADC_TypeDef * ADCx)
201 {
202     uint32_t i;
203 
204     ADCx->CALIB |= (1 << ADC_CALIB_RESET_Pos);
205     for(i = 0; i < 120 * 20; i++) __NOP();          //2个采样时钟周期
206 
207     ADCx->CALIB |= (1 << ADC_CALIB_START_Pos);
208     for(i = 0; i < 120 * 10; i++) __NOP();
209     ADCx->CALIB &=~(1 << ADC_CALIB_START_Pos);
210     while(ADCx->CALIB & ADC_CALIB_BUSY_Msk) __NOP();
211 
212     ADCx->CALIB |= (1 << ADC_CALIB_LOAD_Pos);
213 }
214 
215 /******************************************************************************************************************************************
216 * 函数名称: ADC_Close()
217 * 功能说明: ADC关闭,无法软件启动、或硬件触发ADC转换
218 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
219 * 输    出: 无
220 * 注意事项: 无
221 ******************************************************************************************************************************************/
ADC_Close(ADC_TypeDef * ADCx)222 void ADC_Close(ADC_TypeDef * ADCx)
223 {
224     ADCx->CR &= ~(0x01 << ADC_CR_EN_Pos);
225 }
226 
227 /******************************************************************************************************************************************
228 * 函数名称: ADC_Start()
229 * 功能说明: 软件触发模式下启动ADC转换
230 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
231 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3及其组合(即“按位或”运算)
232 * 输    出: 无
233 * 注意事项: 无
234 ******************************************************************************************************************************************/
ADC_Start(ADC_TypeDef * ADCx,uint32_t seq)235 void ADC_Start(ADC_TypeDef * ADCx, uint32_t seq)
236 {
237     ADCx->GO |= (seq << ADC_GO_SEQ0_Pos);
238 }
239 
240 /******************************************************************************************************************************************
241 * 函数名称: ADC_Stop()
242 * 功能说明: 软件触发模式下停止ADC转换
243 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
244 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3及其组合(即“按位或”运算)
245 * 输    出: 无
246 * 注意事项: 无
247 ******************************************************************************************************************************************/
ADC_Stop(ADC_TypeDef * ADCx,uint32_t seq)248 void ADC_Stop(ADC_TypeDef * ADCx, uint32_t seq)
249 {
250     ADCx->GO &= ~(seq << ADC_GO_SEQ0_Pos);
251 }
252 
253 /******************************************************************************************************************************************
254 * 函数名称: ADC_Read()
255 * 功能说明: 从指定序列读取转换结果
256 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
257 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
258 *           uint32_t *chn           转换结果来自哪个通道,ADC_CH0、ADC_CH1、... ...、ADC_CH10、ADC_CH11
259 * 输    出: uint32_t              读取到的转换结果
260 * 注意事项: 无
261 ******************************************************************************************************************************************/
ADC_Read(ADC_TypeDef * ADCx,uint32_t seq,uint32_t * chn)262 uint32_t ADC_Read(ADC_TypeDef * ADCx, uint32_t seq, uint32_t *chn)
263 {
264     uint32_t idx = ADC_seq2pos(seq) / 8;
265 
266     uint32_t reg = ADCx->SEQ[idx].DR;
267 
268     *chn = 1 << ((reg & ADC_DR_CHNUM_Msk) >> ADC_DR_CHNUM_Pos);
269 
270     return reg & ADC_DR_VALUE_Msk;
271 }
272 
273 /******************************************************************************************************************************************
274 * 函数名称: ADC_DataAvailable()
275 * 功能说明: 指定序列是否有数据可读取
276 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
277 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
278 * 输    出: uint32_t              1 有数据可读取    0 无数据
279 * 注意事项: 无
280 ******************************************************************************************************************************************/
ADC_DataAvailable(ADC_TypeDef * ADCx,uint32_t seq)281 uint32_t ADC_DataAvailable(ADC_TypeDef * ADCx, uint32_t seq)
282 {
283     uint32_t idx = ADC_seq2pos(seq) / 8;
284 
285     return (ADCx->SEQ[idx].SR & ADC_SR_EMPTY_Msk) ? 0 : 1;
286 }
287 
288 
289 /******************************************************************************************************************************************
290 * 函数名称: ADC_INTEn()
291 * 功能说明: 中断使能
292 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
293 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
294 *           uint32_t it             interrupt type,有效值包括ADC_IT_EOC、ADC_IT_FIFO_OVF、ADC_IT_FIFO_HALF、ADC_IT_FIFO_FULL、
295 *                                           ADC_IT_CMP_MAX、ADC_IT_CMP_MIN 及其“或”
296 * 输    出: 无
297 * 注意事项: 无
298 ******************************************************************************************************************************************/
ADC_INTEn(ADC_TypeDef * ADCx,uint32_t seq,uint32_t it)299 void ADC_INTEn(ADC_TypeDef * ADCx, uint32_t seq, uint32_t it)
300 {
301     uint32_t pos = ADC_seq2pos(seq);
302 
303     ADCx->IE |= (it << pos);
304 }
305 
306 /******************************************************************************************************************************************
307 * 函数名称: ADC_INTDis()
308 * 功能说明: 中断禁止
309 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
310 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
311 *           uint32_t it             interrupt type,有效值包括ADC_IT_EOC、ADC_IT_FIFO_OVF、ADC_IT_FIFO_HALF、ADC_IT_FIFO_FULL、
312 *                                           ADC_IT_CMP_MAX、ADC_IT_CMP_MIN 及其“或”
313 * 输    出: 无
314 * 注意事项: 无
315 ******************************************************************************************************************************************/
ADC_INTDis(ADC_TypeDef * ADCx,uint32_t seq,uint32_t it)316 void ADC_INTDis(ADC_TypeDef * ADCx, uint32_t seq, uint32_t it)
317 {
318     uint32_t pos = ADC_seq2pos(seq);
319 
320     ADCx->IE &= ~(it << pos);
321 }
322 
323 /******************************************************************************************************************************************
324 * 函数名称: ADC_INTClr()
325 * 功能说明: 中断标志清除
326 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
327 *           uint32_t seq            指定要设置的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
328 *           uint32_t it             interrupt type,有效值包括ADC_IT_EOC、ADC_IT_FIFO_OVF、ADC_IT_FIFO_HALF、ADC_IT_FIFO_FULL、
329 *                                           ADC_IT_CMP_MAX、ADC_IT_CMP_MIN 及其“或”
330 * 输    出: 无
331 * 注意事项: 无
332 ******************************************************************************************************************************************/
ADC_INTClr(ADC_TypeDef * ADCx,uint32_t seq,uint32_t it)333 void ADC_INTClr(ADC_TypeDef * ADCx, uint32_t seq, uint32_t it)
334 {
335     uint32_t pos = ADC_seq2pos(seq);
336 
337     ADCx->IF = (it << pos);
338 }
339 
340 /******************************************************************************************************************************************
341 * 函数名称: ADC_INTStat()
342 * 功能说明: 中断状态查询
343 * 输    入: ADC_TypeDef * ADCx        指定要设置的ADC,有效值包括ADC0、ADC1
344 *           uint32_t seq            指定要查询的ADC序列,有效值为ADC_SEQ0、ADC_SEQ1、ADC_SEQ2、ADC_SEQ3
345 *           uint32_t it             interrupt type,有效值包括ADC_IT_EOC、ADC_IT_FIFO_OVF、ADC_IT_FIFO_HALF、ADC_IT_FIFO_FULL、
346 *                                           ADC_IT_CMP_MAX、ADC_IT_CMP_MIN 及其“或”
347 * 输    出: uint32_t                  1 中断发生    0 中断未发生
348 * 注意事项: 无
349 ******************************************************************************************************************************************/
ADC_INTStat(ADC_TypeDef * ADCx,uint32_t seq,uint32_t it)350 uint32_t ADC_INTStat(ADC_TypeDef * ADCx, uint32_t seq, uint32_t it)
351 {
352     uint32_t pos = ADC_seq2pos(seq);
353 
354     return (ADCx->IF & (it << pos)) ? 1 : 0;
355 }
356