WXK
2024-09-18 05e2e954bd127de378a9d1dfbb0ed95d725aad63
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
/**************************************************************************//**
 * @file     adc.c
 * @version  V1.00
 * $Revision:  2$
 * $Date: 16/02/25 15:53 $
 * @brief    Panchip series ADC driver source file
 *
 * @note
 * Copyright (C) 2016 Panchip Technology Corp. All rights reserved.
*****************************************************************************/
#include "PanSeries.h"
#include "pan_adc.h"
#include "pan_sys.h"
#include "math.h"
 
/** @addtogroup Panchip_Device_Driver Panchip Device Driver
  @{
*/
 
/** @addtogroup Panchip_ADC_Driver ADC Driver
  @{
*/
 
 
/** @addtogroup Panchip_ADC_EXPORTED_FUNCTIONS ADC Exported Functions
  @{
*/
 
ADC_OPT_T m_adc_opt;
uint32_t global_calc_vbat_mv = 3300;
 
static void bubble_sort_uint16(uint16_t *arr, size_t len)
{
    uint16_t temp;
 
    for (size_t i = 0; i < len - 1; i++) {
        for (size_t j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
 
static void bubble_sort_float(float *arr, size_t len)
{
    float temp;
 
    for (size_t i = 0; i < len - 1; i++) {
        for (size_t j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}
 
/**
  * @brief Init ADC config parameters
  * @param[in] ADCx     Base address of ADC module
  * @param[in] buf_en   Enable ADC buffer or not
  * @return None
  */
bool ADC_Init(ADC_T *ADCx, bool buf_en)
{
    uint32_t tmpreg;
 
    ADCx->BV_CTL |= BIT0; // Enable Bias Voltage Ctrl
    ADCx->BV_CTL = (ADCx->BV_CTL & ~BIT1) | (buf_en ? BIT1 : 0u); // Enable or disable buffer
 
    if (!isFtDataValid)
    {
        return false;
    }
 
    if (m_adc_opt.ft_version >= 6)
    {
        ADCx->CTL2 = m_adc_opt.adc_ctrl2;
        ADCx->EXTSMPT = m_adc_opt.adc_extsmpt;
    }
    else
    {
        // bit13:11 0'b100, bit10:8 0'b101
        tmpreg = ADCx->CTL2;
        tmpreg &= ~(0x7ul << 8);
        tmpreg |= 5 << 8;
        tmpreg &= ~(0x7ul << 11);
        tmpreg |= 4 << 11;
        tmpreg &= ~(0x7ul << 20);
        tmpreg |= 7 << 20;
        tmpreg &= ~(0x7ul << 24);
        tmpreg |= 7 << 24;
        ADCx->CTL2 = tmpreg;
        ADCx->EXTSMPT = 0x00000008;
    }
 
    tmpreg = ADCx->BV_CTL;
    tmpreg &= ~(0x3Fu << 3);
    tmpreg |= m_adc_opt.adc_vbg_1v20_trim << 3;
    ADCx->BV_CTL = tmpreg;
 
    return true;
}
 
/**
  * @brief Prepare ADC VBG fitting curve paramters due to SoC VBAT level
  * @param[in] ADCx Base address of ADC module
  * @return None
  */
void ADC_PrepareVbgCalibData(ADC_T *ADCx)
{
    // NOTE1: We assume ADC is already initialized!
    // NOTE2: We assume ADC input range is already specified!
 
    uint32_t chen_bkp = 0;
    uint32_t sample_code = 0;
 
    if (m_adc_opt.ft_version < 3) {
        // Only use in the SoC which ft_verison >= 3
        return;
    }
 
    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
        // Only use when the ADC reference is 1.2v VBG
        return;
    }
 
    if (ADCx->CHEN) {
        chen_bkp = ADCx->CHEN;
    }
    // Enable channel 10 (internal channel connected to vbat/4)
    ADC_Open(ADCx, ADC_CHEN_CH10_VDD_4_Msk);
 
    // Power on ADC
    ADC_PowerOn(ADCx);
 
    // Delay a while to wait adc stable
    if (m_adc_opt.chip_info >= 0x20) {
        SYS_delay_10nop(500); // Delay 100us+
    } else {
        SYS_delay_10nop(10000); // Delay 3ms+
    }
 
    for (size_t i = 0; i < 8; i++) {
        /* Start sampling */
        ADC_StartConvert(ADC);
        /* Wait for sampling done */
        while (!ADC_IsDataValid(ADC)) {}
        /* Process sampling result data */
        sample_code += ADC_GetConversionData(ADC);
        // Delay 200us+ to wait adc stable
        if (m_adc_opt.chip_info < 0x20) {
            SYS_delay_10nop(1000);
        }
    }
    sample_code /= 8;
 
    // Power down ADC
    ADC_PowerDown(ADC);
 
    if (chen_bkp) {
        ADCx->CHEN = chen_bkp;
    }
 
    global_calc_vbat_mv = ((uint32_t)(m_adc_opt.adc_vbat_k / 10000.0 * sample_code + m_adc_opt.adc_vbat_b / 100.0));;
}
 
 
/**
  * @brief Convert adc code to voltage in uV
  * @param[in] ADCx Base address of ADC module
  * @param[in] adc_code Code sampled by ADC module
  * @return ADC sample voltage output in mV
  */
float ADC_OutputVoltage(ADC_T *ADCx, uint32_t adc_code)
{
    float voltage_mv = 0;
 
    if (ADCx->CTL2 & ADC_SEL_VREF_Msk)  // Ref src is Vbat
    {
        voltage_mv = m_adc_opt.adc_vdd_k / 10000.0 * adc_code + m_adc_opt.adc_vdd_b; // code to code
        voltage_mv = voltage_mv * global_calc_vbat_mv / 4096;
    }
    else    // Ref src is ADC VBG (1.2v)
    {
        if (m_adc_opt.ft_version >= 3)
        {
            uint32_t calc_vbat_mv = global_calc_vbat_mv;
            uint32_t vol_list[] = {1800, 2100, 2400, 2700, 3000, 3300, 3600};
            float V1, V2;
            float A;
            uint8_t vol_index = 0;
            for (uint8_t i = 0; i < 7; i++)
            {
                if (calc_vbat_mv <= vol_list[0])
                {
                    voltage_mv = (float)m_adc_opt.adc_vbg_kb[0].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[0].adc_vbg_b / 100.0;
                    break;
                }
                else if (calc_vbat_mv >= vol_list[6])
                {
                    voltage_mv = (float)m_adc_opt.adc_vbg_kb[6].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[6].adc_vbg_b / 100.0;
                    break;
                }
 
                if (calc_vbat_mv < vol_list[i])
                {
                    vol_index = i;
                    V1 = (float)m_adc_opt.adc_vbg_kb[vol_index - 1].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[vol_index - 1].adc_vbg_b / 100.0;
                    V2 = (float)m_adc_opt.adc_vbg_kb[vol_index].adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_kb[vol_index].adc_vbg_b / 100.0;
                    A = (float)(calc_vbat_mv - vol_list[vol_index - 1]) / 300;
                    voltage_mv = A * V2 + (1 - A) * V1;
                    break;
                }
            }
        }
        else
        {
            voltage_mv = m_adc_opt.adc_vbg_k / 100000.0 * adc_code + m_adc_opt.adc_vbg_b / 100.0;
        }
    }
 
    return voltage_mv;
}
 
/**
  * @brief get caliration params relatd adc ft process
  * @param[in] ADC_OPT_T    hold adc ft parameters
  * @return NULL
  */
void ADC_SetCalirationParams(OTP_STRUCT_T *opt)
{
    m_adc_opt.chip_info = opt->m.chip_info;
    m_adc_opt.ft_version = opt->m.ft_version;
    m_adc_opt.adc_temp_volt = opt->m.adc_temp_volt;
    m_adc_opt.adc_vbg_1v20_trim = opt->m.adc_vbg_1v20_trim;
    m_adc_opt.adc_vbg_b = opt->m.adc_vbg_b;
    m_adc_opt.adc_vbg_k = opt->m.adc_vbg_k;
    m_adc_opt.adc_vdd_b = opt->m.adc_vdd_b;
    m_adc_opt.adc_vdd_k = opt->m.adc_vdd_k;
    m_adc_opt.current_temp_value = opt->m.current_temp_value;
    m_adc_opt.adc_vbat_k = opt->m_v2.adc_vbat_k;
    m_adc_opt.adc_vbat_b = opt->m_v2.adc_vbat_b;
    m_adc_opt.adc_vbat_dtemp_k = opt->m_v2.adc_vbat_dtemp_k;
    m_adc_opt.adc_vbat_dtemp_b = opt->m_v2.adc_vbat_dtemp_b;
    memcpy(m_adc_opt.adc_vbg_kb, opt->m_v2.adc_vbg_kb, sizeof(ADC_VBG_KB_T) * 7);
    m_adc_opt.adc_temp_k = opt->m_v2.adc_temp_k;
    m_adc_opt.adc_ctrl2 = opt->m_v2.adc_ctrl2;
    m_adc_opt.adc_extsmpt = opt->m_v2.adc_extsmpt;
}
 
/**
  * @brief Start sampling many data codes, trim several largest and smallest codes and calculate average valu
  * @param[in] ADCx         Base address of ADC module
  * @param[in] sample_buf   Buffer to temporarily store ADC sample code
  * @param[in] sample_cnt   Total sampling count
  * @param[in] trim_cnt     Total trim count, that means throw away the smallest trim_cnt/2 and largest trim_cnt/2 sample codes
  * @return ADC calculated sample code
  */
uint32_t ADC_SamplingCodeTrimMean(ADC_T *ADCx, uint16_t *sample_buf, uint32_t sample_cnt, uint32_t trim_cnt)
{
    uint32_t sample_code = 0;
 
    // Handle exception
    if (sample_cnt <= trim_cnt) {
        return UINT32_MAX;  // Error occurred
    }
 
    // Start sampling
    for (int i = 0; i < sample_cnt; i++) {
        ADC_StartConvert(ADCx);
        // Wait for sampling done
        while (!ADC_IsDataValid(ADCx)) {
        }
        // Process sampling result data
        sample_buf[i] = ADC_GetConversionData(ADCx);
        // Delay 200us+ to wait adc stable
        if (m_adc_opt.chip_info < 0x20) {
            SYS_delay_10nop(1000);
        }
    }
 
    // Filter out several largest and smallest data and calculate average value
    bubble_sort_uint16(sample_buf, sample_cnt);
    for (int i = trim_cnt / 2; i < (sample_cnt - trim_cnt / 2); i++) {
        sample_code += sample_buf[i];
    }
    sample_code /= sample_cnt - trim_cnt;
 
    return sample_code;
}
 
/**
  * @brief Measure SoC Temperature using the ADC internal Channel 9
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured temperature in Celsius
  */
float ADC_MeasureSocTemperature(ADC_T *ADCx)
{
    uint32_t u32TempReg = 0;
    float temp_param_k = (m_adc_opt.chip_info >= 0x20) ? (m_adc_opt.ft_version >= 6 ? m_adc_opt.adc_temp_k : 0.35) : -0.69; // t = k * (v - vFT) + tFT
    float voltage = 0;
    float temp_voltage_arr[128];
 
    // Enable ADC channel 9
    ADC_Open(ADCx, ADC_CHEN_CH9_TMP_Msk);
 
    // Change ADC Ref to ADC-VBG (1.2v) if is not
    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
        ADC_SelInputRange(ADCx, ADC_INPUTRANGE_LOW);
    }
 
    // Prepare ADC vbg calib paramter due to currnet soc vbat after setting input range to the 0~1.2v ref
    ADC_PrepareVbgCalibData(ADCx);
 
    // Power on ADC
    ADC_PowerOn(ADCx);
 
    // Delay a while to wait adc stable
    if (m_adc_opt.chip_info >= 0x20) {
        SYS_delay_10nop(500); // Delay 100us+
    } else {
        SYS_delay_10nop(50000); // Delay 15ms+
    }
 
    // Start sampling
    for (int i = 0; i < 128; i++) {
        ADC_StartConvert(ADCx);
        // Wait for sampling done
        while (!ADC_IsDataValid(ADCx)) {
        }
        // Process sampling result data
        u32TempReg = ADC_GetConversionData(ADCx);
        temp_voltage_arr[i] = ADC_OutputVoltage(ADCx, u32TempReg);
    }
 
    // Power down ADC
    ADC_PowerDown(ADCx);
 
    // Filter out largest 8 and smallest 8 data and calculate average value
    bubble_sort_float(temp_voltage_arr, 128);
    for (int i = 8; i < 120; i++) {
        voltage += temp_voltage_arr[i];
    }
    voltage /= 112;
 
    // Calculate and return current temp by formula: t = k * (v - vFT) + tFT - tDelta
    return temp_param_k * (voltage - (double)m_adc_opt.adc_temp_volt / 10.0) + (double)m_adc_opt.current_temp_value / 100.0
        - (m_adc_opt.ft_version >= 5 ? ((double)m_adc_opt.adc_vbat_dtemp_k / 10000000.0 * global_calc_vbat_mv + (double)m_adc_opt.adc_vbat_dtemp_b / 1000.0) : 0);
}
 
/**
  * @brief Measure SoC Temperature More Fast using the ADC internal Channel 9
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured temperature in Celsius
  */
float ADC_MeasureSocTemperatureFast(ADC_T *ADCx)
{
    uint32_t temp_code = 0;
    float temp_param_k = (m_adc_opt.chip_info >= 0x20) ? (m_adc_opt.ft_version >= 6 ? m_adc_opt.adc_temp_k : 0.35) : -0.69; // t = k * (v - vFT) + tFT
    float voltage = 0;
    uint16_t temp_code_arr[128];
 
    // Check if current chip support this API
    if (m_adc_opt.chip_info < 0x20) {
        return -1.0f;
    }
 
    // Enable ADC channel 9
    ADC_Open(ADCx, ADC_CHEN_CH9_TMP_Msk);
 
    // Change ADC Ref to ADC-VBG (1.2v) if is not
    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
        ADC_SelInputRange(ADCx, ADC_INPUTRANGE_LOW);
    }
 
    // Prepare ADC vbg calib paramter due to currnet soc vbat after setting input range to the 0~1.2v ref
    ADC_PrepareVbgCalibData(ADCx);
 
    // Power on ADC
    ADC_PowerOn(ADCx);
 
    // Delay a while to wait adc stable
    SYS_delay_10nop(500); // Delay 100us+
 
    // Start sampling
    for (int i = 0; i < 128; i++) {
        ADC_StartConvert(ADCx);
        // Wait for sampling done
        while (!ADC_IsDataValid(ADCx)) {
        }
        // Process sampling result data
        temp_code_arr[i] = ADC_GetConversionData(ADCx);
    }
 
    // Power down ADC
    ADC_PowerDown(ADCx);
 
    // Filter out largest 8 and smallest 8 data and calculate average value
    bubble_sort_uint16(temp_code_arr, 128);
    for (int i = 8; i < 120; i++) {
        temp_code += temp_code_arr[i];
    }
    temp_code /= 112;
 
    // Calculate voltage of temp sensor
    voltage = ADC_OutputVoltage(ADCx, temp_code);
 
    // Calculate and return current temp by formula: t = k * (v - vFT) + tFT - tDelta
    return temp_param_k * (voltage - (double)m_adc_opt.adc_temp_volt / 10.0) + (double)m_adc_opt.current_temp_value / 100.0
        - (m_adc_opt.ft_version >= 5 ? ((double)m_adc_opt.adc_vbat_dtemp_k / 10000000.0 * global_calc_vbat_mv + (double)m_adc_opt.adc_vbat_dtemp_b / 1000.0) : 0);
}
 
/**
  * @brief Measure SoC VBAT using the ADC internal Channel 10
  * @param[in] ADCx Base address of ADC module
  * @return ADC measured VBAT voltage in mV
  */
uint16_t ADC_MeasureSocVbat(ADC_T *ADCx)
{
    uint32_t u32TempReg = 0;
    float voltage = 0;
    float temp_voltage_arr[32];
 
    // Enable channel 10 (internal channel connected to vbat/4)
    ADC_Open(ADCx, ADC_CHEN_CH10_VDD_4_Msk);
 
    // Change ADC Ref to ADC-VBG (1.2v) if is not
    if (ADCx->CTL2 & ADC_SEL_VREF_Msk) {
        ADC_SelInputRange(ADCx, ADC_INPUTRANGE_LOW);
    }
 
//    if (m_adc_opt.chip_info < 0x20) {
//        // Prepare ADC vbg calib paramter due to currnet soc vbat after setting input range to the 0~1.2v ref
//        ADC_PrepareVbgCalibData(ADCx);
//    }
 
    // Power on ADC
    ADC_PowerOn(ADCx);
 
    // Delay a while to wait adc stable
    if (m_adc_opt.chip_info >= 0x20) {
        SYS_delay_10nop(500); // Delay 100us+
    } else {
        SYS_delay_10nop(50000); // Delay 15ms+
    }
 
    // Start sampling
    for (int i = 0; i < 32; i++) {
        ADC_StartConvert(ADCx);
        // Wait for sampling done
        while (!ADC_IsDataValid(ADCx)) {
        }
        // Process sampling result data
        u32TempReg = ADC_GetConversionData(ADCx);
        if (m_adc_opt.ft_version >= 3) {
            temp_voltage_arr[i] = ((float)(m_adc_opt.adc_vbat_k / 10000.0 * u32TempReg + m_adc_opt.adc_vbat_b / 100.0));
        } else {
            temp_voltage_arr[i] = ADC_OutputVoltage(ADCx, u32TempReg);
        }
    }
 
    // Power down ADC
    ADC_PowerDown(ADCx);
 
    // Filter out largest 8 and smallest 8 data and calculate average value
    bubble_sort_float(temp_voltage_arr, 32);
    for (int i = 8; i < 24; i++) {
        voltage += temp_voltage_arr[i];
    }
    voltage /= 16;
 
    if (m_adc_opt.ft_version < 3) {
        voltage = (uint16_t)(4 * voltage + 0.5); // Rounding off
    }
 
    return voltage;
}
 
/**
  * @brief Disable ADC Power
  * @param[in] adc Base address of ADC module
  * @return None
  */
void ADC_Disable(ADC_T *ADCx)
{
//    SYS->IPRST1 |= SYS_IPRST1_ADCRST_Msk;
//    SYS->IPRST1 &= ~SYS_IPRST1_ADCRST_Msk;
    
    ADCx->CTL &= ~ADC_CTL_ADCEN_Msk;
    return;
 
}
 
/**
  * @brief Disable ADC module
  * @param[in] adc Base address of ADC module
  * @return None
  */
void ADC_Close(void)
{
//    SYS->IPRST1 |= SYS_IPRST1_ADCRST_Msk;
//    SYS->IPRST1 &= ~SYS_IPRST1_ADCRST_Msk;
//    return;
 
}
 
/**
  * @brief Configure the hardware trigger condition and enable hardware trigger
  * @param[in] adc Base address of ADC module
  * @param[in] u32Source Decides the hardware trigger source. Valid values are:
  *                 - \ref ADC_TRIGGER_BY_EXT_PIN
  *                 - \ref ADC_TRIGGER_BY_PWM
  * @param[in] u32Param While ADC trigger by PWM, this parameter is used to set the delay between PWM
  *                     trigger and ADC conversion. Valid values are from 0 ~ 0xFF, and actual delay
  *                     time is (4 * u32Param * HCLK). While ADC trigger by external pin, this parameter
  *                     is used to set trigger condition. Valid values are:
  *                 - \ref ADC_FALLING_EDGE_TRIGGER
  *                 - \ref ADC_RISING_EDGE_TRIGGER
  * @return None
  */
void ADC_EnableHWTrigger(ADC_T *ADCx,uint32_t Source,uint32_t TrgCondition)
{
    ADCx->CTL &= ~(ADC_TRIGGER_BY_PWM | ADC_RISING_EDGE_TRIGGER | ADC_CTL_HWTRGEN_Msk);
    if(Source == ADC_TRIGGER_BY_EXT_PIN) {
        ADCx->CTL &= ~(ADC_CTL_HWTRGSEL_Msk | ADC_CTL_HWTRGCOND_Msk);
        ADCx->CTL |= (Source | TrgCondition);
    } else {
        ADCx->CTL |=  Source;
    }
    ADCx->CTL |=  ADC_CTL_HWTRGEN_Msk;
    return;
}
 
/**
  * @brief Disable hardware trigger ADC function.
  * @param[in] adc Base address of ADC module
  * @return None
  */
void ADC_DisableHWTrigger(ADC_T *ADCx)
{
    ADCx->CTL &= ~(ADC_TRIGGER_BY_PWM | ADC_RISING_EDGE_TRIGGER | ADC_CTL_HWTRGEN_Msk);
}
 
/**
  * @brief Enable the interrupt(s) selected by u32Mask parameter.
  * @param[in] adc Base address of ADC module
  * @param[in] u32Mask  The combination of interrupt status bits listed below. Each bit
  *                     corresponds to a interrupt status. This parameter decides which
  *                     interrupts will be enabled.
  *                     - \ref ADC_ADIF_INT
  *                     - \ref ADC_CMP0_INT
  *                     - \ref ADC_CMP1_INT
  * @return None
  */
void ADC_EnableInt(ADC_T *ADCx, uint32_t Mask)
{
    if(Mask & ADC_ADIF_INT)
        ADCx->CTL |= ADC_CTL_ADCIEN_Msk;
    if(Mask & ADC_CMP0_INT)
        ADCx->CMP0 |= ADC_CMP0_ADCMPIE_Msk;
    if(Mask & ADC_CMP1_INT)
        ADCx->CMP1 |= ADC_CMP1_ADCMPIE_Msk;
 
    return;
}
 
/**
  * @brief Disable the interrupt(s) selected by u32Mask parameter.
  * @param[in] adc Base address of ADC module
  * @param[in] u32Mask  The combination of interrupt status bits listed below. Each bit
  *                     corresponds to a interrupt status. This parameter decides which
  *                     interrupts will be disabled.
  *                     - \ref ADC_ADIF_INT
  *                     - \ref ADC_CMP0_INT
  *                     - \ref ADC_CMP1_INT
  * @return None
  */
void ADC_DisableInt(ADC_T *ADCx, uint32_t Mask)
{
    if(Mask & ADC_ADIF_INT)
        ADCx->CTL &= ~ADC_CTL_ADCIEN_Msk;
    if(Mask & ADC_CMP0_INT)
        ADCx->CMP0 &= ~ADC_CMP0_ADCMPIE_Msk;
    if(Mask & ADC_CMP1_INT)
        ADCx->CMP1 &= ~ADC_CMP1_ADCMPIE_Msk;
 
    return;
}
 
/**
  * @brief ADC PWM Sequential Mode Control.
  * @param[in] adc Base address of ADC module
  * @param[in] u32SeqTYPE   This parameter decides which type will be selected.
  *                     - \ref ADC_SEQMODE_TYPE_23SHUNT
  *                     - \ref ADC_SEQMODE_TYPE_1SHUNT
  * @param[in] u32ModeSel  This parameter decides which mode will be selected.
  *                     - \ref ADC_SEQMODE_MODESELECT_CH01
  *                     - \ref ADC_SEQMODE_MODESELECT_CH12
  *                     - \ref ADC_SEQMODE_MODESELECT_CH02
  *                     - \ref ADC_SEQMODE_MODESELECT_ONE
  * @return None
  */
void ADC_SeqModeEnable(ADC_T *ADCx, uint32_t SeqType, uint32_t ModeSel)
{
    // Enable ADC Sequential Mode
    ADCx->SEQCTL = ADCx->SEQCTL  | ADC_SEQCTL_SEQEN_Msk;
    // Select ADC Sequential Mode Type
    ADCx->SEQCTL = (ADCx->SEQCTL & ~(ADC_SEQCTL_SEQTYPE_Msk)) | (SeqType << ADC_SEQCTL_SEQTYPE_Pos);
    // Select ADC Sequential Mode Type
    ADCx->SEQCTL = (ADCx->SEQCTL & ~(ADC_SEQCTL_MODESEL_Msk)) | (ModeSel << ADC_SEQCTL_MODESEL_Pos);
 
    return;
}
 
/**
  * @brief ADC PWM Sequential Mode PWM Trigger Source and type.
  * @param[in] adc Base address of ADC module
  * @param[in] u32SeqModeTriSrc1  This parameter decides first PWM trigger source and type.
  *
  *
  * @return None
  */
void ADC_SeqModeTriggerSrc(ADC_T *ADCx, uint32_t SeqModeTriSrc)
{
    // Select PWM Trigger Source Selection for TRG1CTL or TRG2CTL
    if(ADCx->SEQCTL & ADC_SEQCTL_TRG_SEL_Msk)
        ADCx->SEQCTL = (ADCx->SEQCTL & ~(ADC_SEQCTL_TRG2CTL_Msk)) | (SeqModeTriSrc << ADC_SEQCTL_TRG2CTL_Pos);
    else
        ADCx->SEQCTL = (ADCx->SEQCTL & ~(ADC_SEQCTL_TRG1CTL_Msk)) | (SeqModeTriSrc << ADC_SEQCTL_TRG1CTL_Pos);
    return;
}
/**
  * @brief Configure the comparator 0 and enable it
  * @param[in] adc Base address of ADC module
  * @param[in] ChNum  Specifies the source channel, valid value are from 0 to 7
  * @param[in] CmpCondition Specifies the compare condition
  *                     - \ref ADC_CMP0_LESS_THAN
  *                     - \ref ADC_CMP0_GREATER_OR_EQUAL_TO
  * @param[in] CmpData Specifies the compare value. Valid value are between 0 ~ 0x3FF
  * @param[in] MatchCnt Specifies the match count setting, valid values are between 1~16
  * @param[in] CmpSelect comparator select,0 or 1
  * @return None
  * @details For example, ADC_CompareEnable(ADC, 5, ADC_CMP_GREATER_OR_EQUAL_TO, 0x800, 10,ADC_COMPARATOR_0);
  *          Means ADC will assert comparator 0 flag if channel 5 conversion result is 
  *          greater or equal to 0x800 for 10 times continuously.
  * \hideinitializer
  */ 
void ADC_CompareEnable(ADC_T *ADCx,
                       uint32_t ChNum,
                       uint32_t CmpCondition,
                       uint32_t CmpData,
                       uint32_t MatchCnt,
                       uint32_t CmpSelect)
{
    uint32_t TmpRegister;
    
    if(ADC_COMPARATOR_1 == CmpSelect)
        TmpRegister = ADC->CMP1;
    else
        TmpRegister = ADC->CMP0;
    
    TmpRegister |= (ChNum << ADC_CMP0_CMPCH_Pos); //select compare channel
    TmpRegister |= CmpCondition;    //select compare condition(less than or greater than )
    TmpRegister |= (CmpData << ADC_CMP0_CMPDAT_Pos);    //set expect compare data
    TmpRegister |= ((MatchCnt - 1) << ADC_CMP0_CMPMCNT_Pos); //set compare match count
    if(ADC_COMPARATOR_1 == CmpSelect){
        TmpRegister |= ADC_CMP1_ADCMPEN_Msk;    //comparator enable
        ADC->CMP1 = TmpRegister;
    }
    else{
        TmpRegister |= ADC_CMP0_ADCMPEN_Msk;    //comparator enable  
        ADC->CMP0 = TmpRegister;
    }        
}
 
/**
  * @brief set ADC PWM one channel Sequential Mode configuration.
  * @param[in] adc Base address of ADC module
  * @param[in] Trig  This parameter decides first PWM trigger source and type.
  * @param[in] Level  This parameter decides fifo threshold value.
  * @param[in] DmaEn  This parameter decides dma is used or not.
  * @param[in] HwClrEN  This parameter decides PWM trigger flag cleared by hardware or software.
  * @param[in] AdcCh  This parameter decides which adc channel selected.
  * @return None
  */
void ADC_SeqOneChModeConfig(ADC_T *ADCx, 
                            uint32_t Trig,
                            uint8_t Level,
                            uint8_t DmaEn,
                            uint8_t HwClrEN)
{
    // ADC Hardware External trigger Enabled by PMW
    ADC_EnableHWTrigger(ADCx, ADC_TRIGGER_BY_PWM, Trig);
    ADC_SetFifoTrigLevel(ADCx,Level);
    if(DmaEn)
        ADC_DmaModeEnable(ADCx,ENABLE);
    else
        ADC_DmaModeEnable(ADCx,DISABLE);
 
    // ADC Sequential mode & type Enable
    ADC_SeqModeEnable(ADCx,ADC_SEQMODE_TYPE_23SHUNT,ADC_SEQMODE_MODESELECT_ONE);
    ADC_SeqModeOneChEn(ADCx,ENABLE);
    if(HwClrEN)
            ADC_ClearByHw(ADCx,ENABLE);
    else
            ADC_ClearByHw(ADCx,DISABLE);        
}
 
/*@}*/ /* end of group Panchip_ADC_EXPORTED_FUNCTIONS */
 
/*@}*/ /* end of group Panchip_ADC_Driver */
 
/*@}*/ /* end of group Panchip_Device_Driver */
 
/*** (C) COPYRIGHT 2016 Panchip Technology Corp. ***/