1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_adc12_drv.h"
9 #include "hpm_soc_feature.h"
10
adc12_get_default_config(adc12_config_t * config)11 void adc12_get_default_config(adc12_config_t *config)
12 {
13 config->res = adc12_res_12_bits;
14 config->conv_mode = adc12_conv_mode_oneshot;
15 config->adc_clk_div = 1;
16 config->wait_dis = 0;
17 config->sel_sync_ahb = true;
18 config->adc_ahb_en = false;
19 }
20
adc12_get_channel_default_config(adc12_channel_config_t * config)21 void adc12_get_channel_default_config(adc12_channel_config_t *config)
22 {
23 config->ch = 0;
24 config->diff_sel = adc12_sample_signal_single_ended;
25 config->sample_cycle = 10;
26 config->sample_cycle_shift = 0;
27 config->thshdh = 0;
28 config->thshdl = 0;
29 }
30
adc12_do_calibration(ADC12_Type * ptr,adc12_sample_signal_t diff_sel)31 static hpm_stat_t adc12_do_calibration(ADC12_Type *ptr, adc12_sample_signal_t diff_sel)
32 {
33 uint8_t cal_out;
34 uint32_t loop_cnt = ADC12_SOC_CALIBRATION_WAITING_LOOP_CNT;
35
36 if (ADC12_IS_SIGNAL_TYPE_INVALID(diff_sel)) {
37 return status_invalid_argument;
38 }
39
40 /*Set diff_sel temporarily */
41 ptr->SAMPLE_CFG[0] = ADC12_SAMPLE_CFG_DIFF_SEL_SET(diff_sel);
42
43 /* Set resetcal and resetadc */
44 ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_RESETCAL_MASK;
45
46 /* Clear resetcal and resetadc */
47 ptr->ANA_CTRL0 &= ~(ADC12_ANA_CTRL0_RESETCAL_MASK | ADC12_ANA_CTRL0_RESETADC_MASK);
48
49 /* Set startcal */
50 ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_STARTCAL_MASK;
51
52 /* Clear startcal */
53 ptr->ANA_CTRL0 &= ~ADC12_ANA_CTRL0_STARTCAL_MASK;
54
55 /* Set HW rearm_en */
56 ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_REARM_EN_MASK;
57
58 /* Polling calibration status */
59 while (ADC12_ANA_STATUS_CALON_GET(ptr->ANA_STATUS) && loop_cnt--) {
60 /* TODO: Call a common delay function */
61 }
62
63 /* Check if the calibration is timeout */
64 if (loop_cnt == 0) {
65 return status_timeout;
66 }
67
68 /* Read calculation result */
69 cal_out = ADC12_ANA_STATUS_CAL_OUT_GET(ptr->ANA_STATUS);
70
71 /* Update cal_out */
72 if (diff_sel == adc12_sample_signal_single_ended) {
73 ptr->ANA_CTRL0 = (ptr->ANA_CTRL0 & ~ADC12_ANA_CTRL0_CAL_VAL_SE_MASK)
74 | ADC12_ANA_CTRL0_CAL_VAL_SE_SET(cal_out);
75 } else {
76 ptr->ANA_CTRL0 = (ptr->ANA_CTRL0 & ~ADC12_ANA_CTRL0_CAL_VAL_DIFF_MASK)
77 | ADC12_ANA_CTRL0_CAL_VAL_DIFF_SET(cal_out);
78 }
79
80 return status_success;
81 }
82
adc12_init(ADC12_Type * ptr,adc12_config_t * config)83 hpm_stat_t adc12_init(ADC12_Type *ptr, adc12_config_t *config)
84 {
85 uint32_t adc_clk_div;
86
87 /**
88 * disable adc
89 * When the adc is processing data, it will generate an error to initialize the adc again,
90 * so you need to shut down the adc before initializing it.
91 */
92
93 ptr->ANA_CTRL0 &= ~(ADC12_ANA_CTRL0_ENADC_MASK);
94
95 /* Check the resolution */
96 if (config->res > adc12_res_12_bits) {
97 return status_invalid_argument;
98 }
99
100 /* Set resolution */
101 ptr->ANA_CTRL1 = (ptr->ANA_CTRL1 & ~ADC12_ANA_CTRL1_SELRES_MASK)
102 | ADC12_ANA_CTRL1_SELRES_SET(config->res);
103
104 /* Set convert clock number and clock period */
105 if (config->adc_clk_div > ADC12_CONV_CFG1_CLOCK_DIVIDER_MASK) {
106 return status_invalid_argument;
107 }
108
109 /* Set ADC minimum conversion cycle and ADC clock divider */
110 ptr->CONV_CFG1 = ADC12_CONV_CFG1_CONVERT_CLOCK_NUMBER_SET(2 * config->res + 7)
111 | ADC12_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div);
112
113 /* Set ADC Config0 */
114 ptr->ADC_CFG0 = ADC12_ADC_CFG0_SEL_SYNC_AHB_SET(config->sel_sync_ahb)
115 | ADC12_ADC_CFG0_ADC_AHB_EN_SET(config->adc_ahb_en);
116
117 /* Set wait_dis */
118 if (config->conv_mode == adc12_conv_mode_oneshot) {
119 /* Set wait_dis */
120 ptr->BUF_CFG0 = ADC12_BUF_CFG0_WAIT_DIS_SET(config->wait_dis);
121 }
122
123 /*-------------------------------------------------------------------------------
124 * Calibration
125 *------------------------------------------------------------------------------
126 */
127 /* Set enldo */
128 ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_ENLDO_MASK;
129
130 /* TODO: wait 20us after setting enlado for adc0~adc2 */
131
132 adc_clk_div = config->adc_clk_div;
133
134 if (adc_clk_div == ADC12_SOC_CLOCK_CLK_DIV) {
135 ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC12_CONV_CFG1_CLOCK_DIVIDER_MASK)
136 | ADC12_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div + 1);
137 }
138
139 /* Set enadc */
140 ptr->ANA_CTRL0 |= ADC12_ANA_CTRL0_ENADC_MASK;
141
142 /* Do a calibration for single-ended mode */
143 adc12_do_calibration(ptr, adc12_sample_signal_single_ended);
144
145 /* Do a calibration for differential mode */
146 adc12_do_calibration(ptr, adc12_sample_signal_differential);
147
148 /* Set ADC clock divider */
149 if (adc_clk_div == ADC12_SOC_CLOCK_CLK_DIV) {
150 ptr->CONV_CFG1 = (ptr->CONV_CFG1 & ~ADC12_CONV_CFG1_CLOCK_DIVIDER_MASK)
151 | ADC12_CONV_CFG1_CLOCK_DIVIDER_SET(config->adc_clk_div);
152 }
153
154 /*-------------------------------------------------------------------------------
155 * End of calibration
156 *------------------------------------------------------------------------------
157 */
158
159 return status_success;
160 }
161
adc12_init_channel(ADC12_Type * ptr,adc12_channel_config_t * config)162 hpm_stat_t adc12_init_channel(ADC12_Type *ptr, adc12_channel_config_t *config)
163 {
164 /* Check the specified channel number */
165 if (ADC12_IS_CHANNEL_INVALID(ptr, config->ch)) {
166 return status_invalid_argument;
167 }
168
169 /* Set warning threshold */
170 ptr->PRD_CFG[config->ch].PRD_THSHD_CFG = ADC12_PRD_CFG_PRD_THSHD_CFG_THSHDH_SET(config->thshdh)
171 | ADC12_PRD_CFG_PRD_THSHD_CFG_THSHDL_SET(config->thshdl);
172
173 /* Select single-ended mode or differential mode */
174 /* Set ADC sample cycles multiple */
175 /* Set ADC sample cycles */
176 ptr->SAMPLE_CFG[config->ch] = ADC12_SAMPLE_CFG_DIFF_SEL_SET(config->diff_sel)
177 | ADC12_SAMPLE_CFG_SAMPLE_CLOCK_NUMBER_SHIFT_SET(config->sample_cycle_shift)
178 | ADC12_SAMPLE_CFG_SAMPLE_CLOCK_NUMBER_SET(config->sample_cycle);
179
180 return status_success;
181 }
182
adc12_init_seq_dma(ADC12_Type * ptr,adc12_dma_config_t * dma_config)183 hpm_stat_t adc12_init_seq_dma(ADC12_Type *ptr, adc12_dma_config_t *dma_config)
184 {
185 /* Check the DMA buffer length */
186 if (ADC12_IS_SEQ_DMA_BUFF_LEN_INVLAID(dma_config->buff_len_in_4bytes)) {
187 return status_invalid_argument;
188 }
189
190 /* Reset ADC DMA */
191 ptr->SEQ_DMA_CFG |= ADC12_SEQ_DMA_CFG_DMA_RST_MASK;
192
193 /* Reset memory to clear all of cycle bits */
194 memset(dma_config->start_addr, 0x00, dma_config->buff_len_in_4bytes * sizeof(uint32_t));
195
196 /* De-reset ADC DMA */
197 ptr->SEQ_DMA_CFG &= ~ADC12_SEQ_DMA_CFG_DMA_RST_MASK;
198
199 /* Set ADC DMA target address which should be 4-byte aligned */
200 ptr->SEQ_DMA_ADDR = (uint32_t)dma_config->start_addr & ADC12_SEQ_DMA_ADDR_TAR_ADDR_MASK;
201
202 /* Set ADC DMA memory dword length */
203 ptr->SEQ_DMA_CFG = (ptr->SEQ_DMA_CFG & ~ADC12_SEQ_DMA_CFG_BUF_LEN_MASK)
204 | ADC12_SEQ_DMA_CFG_BUF_LEN_SET(dma_config->buff_len_in_4bytes - 1);
205
206 /* Set stop_en and stop_pos */
207 if (dma_config->stop_en) {
208 ptr->SEQ_DMA_CFG = (ptr->SEQ_DMA_CFG & ~ADC12_SEQ_DMA_CFG_STOP_POS_MASK)
209 | ADC12_SEQ_DMA_CFG_STOP_EN_MASK
210 | ADC12_SEQ_DMA_CFG_STOP_POS_SET(dma_config->stop_pos);
211 }
212
213 return status_success;
214 }
215
adc12_set_prd_config(ADC12_Type * ptr,adc12_prd_config_t * config)216 hpm_stat_t adc12_set_prd_config(ADC12_Type *ptr, adc12_prd_config_t *config)
217 {
218 /* Check the specified channel number */
219 if (ADC12_IS_CHANNEL_INVALID(ptr, config->ch)) {
220 return status_invalid_argument;
221 }
222
223 /* Check the prescale */
224 if (config->prescale > (ADC12_PRD_CFG_PRD_CFG_PRESCALE_MASK >> ADC12_PRD_CFG_PRD_CFG_PRESCALE_SHIFT)) {
225 return status_invalid_argument;
226 }
227
228 /* Set periodic prescale */
229 ptr->PRD_CFG[config->ch].PRD_CFG = (ptr->PRD_CFG[config->ch].PRD_CFG & ~ADC12_PRD_CFG_PRD_CFG_PRESCALE_MASK)
230 | ADC12_PRD_CFG_PRD_CFG_PRESCALE_SET(config->prescale);
231
232
233 /* Set period count */
234 ptr->PRD_CFG[config->ch].PRD_CFG = (ptr->PRD_CFG[config->ch].PRD_CFG & ~ADC12_PRD_CFG_PRD_CFG_PRD_MASK)
235 | ADC12_PRD_CFG_PRD_CFG_PRD_SET(config->period_count);
236
237 return status_success;
238 }
239
adc12_trigger_seq_by_sw(ADC12_Type * ptr)240 void adc12_trigger_seq_by_sw(ADC12_Type *ptr)
241 {
242 ptr->SEQ_CFG0 |= ADC12_SEQ_CFG0_SW_TRIG_MASK;
243 }
244
245 /* Note: the sequence length can not be larger or equal than 2 in HPM6750EVK Revision A0 */
adc12_set_seq_config(ADC12_Type * ptr,adc12_seq_config_t * config)246 hpm_stat_t adc12_set_seq_config(ADC12_Type *ptr, adc12_seq_config_t *config)
247 {
248 /* Check sequence length */
249 if (ADC12_IS_SEQ_LEN_INVLAID(config->seq_len)) {
250 return status_invalid_argument;
251 }
252
253 ptr->SEQ_CFG0 = ADC12_SEQ_CFG0_SEQ_LEN_SET(config->seq_len - 1)
254 | ADC12_SEQ_CFG0_RESTART_EN_SET(config->restart_en)
255 | ADC12_SEQ_CFG0_CONT_EN_SET(config->cont_en)
256 | ADC12_SEQ_CFG0_SW_TRIG_EN_SET(config->sw_trig_en)
257 | ADC12_SEQ_CFG0_HW_TRIG_EN_SET(config->hw_trig_en);
258
259 /* Set sequence queue */
260 for (int i = 0; i < config->seq_len; i++) {
261 /* Check the specified channel number */
262 if (ADC12_IS_CHANNEL_INVALID(ptr, config->queue[i].ch)) {
263 return status_invalid_argument;
264 }
265
266 ptr->SEQ_QUE[i] = ADC12_SEQ_QUE_SEQ_INT_EN_SET(config->queue[i].seq_int_en)
267 | ADC12_SEQ_QUE_CHAN_NUM_4_0_SET(config->queue[i].ch);
268 }
269
270 return status_success;
271 }
272
adc12_set_pmt_config(ADC12_Type * ptr,adc12_pmt_config_t * config)273 hpm_stat_t adc12_set_pmt_config(ADC12_Type *ptr, adc12_pmt_config_t *config)
274 {
275 uint32_t temp = 0;
276
277 /* Check the specified trigger length */
278 if (ADC12_IS_TRIG_LEN_INVLAID(config->trig_len)) {
279 return status_invalid_argument;
280 }
281
282 temp |= ADC12_CONFIG_TRIG_LEN_SET(config->trig_len - 1);
283
284 for (int i = 0; i < config->trig_len; i++) {
285 if (ADC12_IS_CHANNEL_INVALID(ptr, config->trig_ch)) {
286 return status_invalid_argument;
287 }
288
289 temp |= config->inten[i] << (ADC12_CONFIG_INTEN0_SHIFT + i * ADC_SOC_CONFIG_INTEN_CHAN_BIT_SIZE)
290 | config->adc_ch[i] << (ADC12_CONFIG_CHAN0_SHIFT + i * ADC_SOC_CONFIG_INTEN_CHAN_BIT_SIZE);
291 }
292
293 ptr->CONFIG[config->trig_ch] = temp;
294
295 return status_success;
296 }
297
adc12_get_oneshot_result(ADC12_Type * ptr,uint8_t ch,uint16_t * result)298 hpm_stat_t adc12_get_oneshot_result(ADC12_Type *ptr, uint8_t ch, uint16_t *result)
299 {
300 /* Check the specified channel number */
301 if (ADC12_IS_CHANNEL_INVALID(ptr, ch)) {
302 return status_invalid_argument;
303 }
304
305 *result = ADC12_BUS_RESULT_CHAN_RESULT_GET(ptr->BUS_RESULT[ch]);
306
307 return status_success;
308 }
309
adc12_get_prd_result(ADC12_Type * ptr,uint8_t ch,uint16_t * result)310 hpm_stat_t adc12_get_prd_result(ADC12_Type *ptr, uint8_t ch, uint16_t *result)
311 {
312 /* Check the specified channel number */
313 if (ADC12_IS_CHANNEL_INVALID(ptr, ch)) {
314 return status_invalid_argument;
315 }
316
317 *result = ptr->PRD_CFG[ch].PRD_RESULT;
318
319 return status_success;
320 }
321