• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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