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