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
|
// ADC functions on Huada HC32F460
//
// Copyright (C) 2022 Steven Gotthardt <gotthardt@gmail.com>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "generic/misc.h" // timer_from_us
#include "command.h" // shutdown
#include "board/gpio.h" // gpio_adc_setup
#include "board/internal.h" // GPIO
#include "sched.h" // sched_shutdown
// library
#include "hc32f460_adc.h"
#include "hc32f460_pwc.h"
#include "hc32f460_gpio.h"
#define ADC_RESOLUTION_12BIT (12u)
#define ADC_RESOLUTION_10BIT (10u)
#define ADC_RESOLUTION_8BIT (8u)
#define ADC1_RESOLUTION (ADC_RESOLUTION_12BIT)
#define ADC1_PRECISION (1ul << ADC1_RESOLUTION)
#if ADC1_RESOLUTION == ADC_RESOLUTION_12BIT
#define AdcResolution AdcResolution_12Bit
#elif ADC1_RESOLUTION == ADC_RESOLUTION_10BIT
#define AdcResolution AdcResolution_10Bit
#else
#define AdcResolution AdcResolution_8Bit
#endif
/* Timeout value definitions. Found in example code */
#define TIMEOUT_VAL (30u)
DECL_CONSTANT("ADC_MAX", ADC1_PRECISION-1);
// These pins can be used for ADC
static const uint8_t adc_gpio[] = {
GPIO('A', 0), // Chan 0
GPIO('A', 1), // Chan 1
GPIO('A', 2), // Chan 2
GPIO('A', 3), // Chan 3
GPIO('A', 4), // Chan 4
GPIO('A', 5), // Chan 5
GPIO('A', 6), // Chan 6
GPIO('A', 7), // Chan 7
GPIO('B', 0), // Chan 8
GPIO('B', 1), // Chan 9
GPIO('C', 0), // Chan 10 // TBed on TriGorilla
GPIO('C', 1), // Chan 11 // THead on TriGorilla
GPIO('C', 2), // Chan 12
GPIO('C', 3), // Chan 13
GPIO('C', 4), // Chan 14 // TBed on aquilla
GPIO('C', 5), // Chan 15 // THead on aquilla
};
struct gpio_adc
gpio_adc_setup(uint32_t gpio)
{
// validate pin in adc_pins table
int chan;
for (chan=0; ; chan++)
{
if (chan >= ARRAY_SIZE(adc_gpio))
{
shutdown("Not a valid ADC pin");
}
if (adc_gpio[chan] == gpio)
{
break;
}
}
// set as analog
gpio_peripheral(gpio, Pin_Mode_Ana, 0);
uint8_t sampleTime[ARRAY_SIZE(adc_gpio)] = { TIMEOUT_VAL }; // all chans
stc_adc_ch_cfg_t stcAdcChan;
stcAdcChan.u32Channel = 1 << chan;
stcAdcChan.u8Sequence = ADC_SEQ_A; // all conversions are in SEQ A
stcAdcChan.pu8SampTime = sampleTime;
ADC_AddAdcChannel(M4_ADC1, &stcAdcChan);
return (struct gpio_adc){ .chan = chan };
}
// Try to sample a value. Returns zero if sample ready, otherwise
// returns the number of clock ticks the caller should wait before
// retrying this function.
uint32_t
gpio_adc_sample(struct gpio_adc g)
{
// true if the sequence is finished
if (ADC_GetEocFlag(M4_ADC1, ADC_SEQ_A))
{
// all conversions are done - clear the flag
ADC_ClrEocFlag(M4_ADC1, ADC_SEQ_A);
return 0;
}
else if (M4_ADC1->STR & 1)
{
// running but not done yet
return timer_from_us(TIMEOUT_VAL/2);
}
else
{
// not running - so start
ADC_StartConvert(M4_ADC1);
}
return timer_from_us(TIMEOUT_VAL);
}
// Read a value; use only after gpio_adc_sample() returns zero
uint16_t
gpio_adc_read(struct gpio_adc g)
{
// return the one we want...
return ADC_GetValue(M4_ADC1, g.chan);
}
// Cancel a sample that may have been started with gpio_adc_sample()
void
gpio_adc_cancel_sample(struct gpio_adc g)
{
ADC_StopConvert(M4_ADC1);
}
// The clocks are already set by the loader.
// There is ADC1 and ADC2. Sequences do all channels at once.
void
adc_init(void)
{
// PCLK2 (ADC clock) is 'divide by 4', Max ADC clock is 60MHz
stc_adc_init_t stcAdcInit = {0};
stcAdcInit.enResolution = AdcResolution; // see define above
stcAdcInit.enDataAlign = AdcDataAlign_Right;
stcAdcInit.enAutoClear = AdcClren_Disable;
stcAdcInit.enScanMode = AdcMode_SAOnce;
// power-on ADC
PWC_Fcg3PeriphClockCmd(PWC_FCG3_PERIPH_ADC1, Enable);
// only using ADC1
ADC_Init(M4_ADC1, &stcAdcInit);
}
DECL_INIT(adc_init);
|