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