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