1 /******************************************************************************
2 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
3 * All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************/
18
19 #include "adc.h"
20 #include "audio.h"
21 #include "compiler.h"
22
23 _attribute_data_retention_sec_ unsigned short g_adc_vref = 1175; // default ADC ref voltage (unit:mV)
24 volatile unsigned char g_adc_pre_scale;
25 volatile unsigned char g_adc_vbat_divider;
26
27 dma_chn_e adc_dma_chn;
28 dma_config_t adc_rx_dma_config = {
29 .dst_req_sel = 0,
30 .src_req_sel = DMA_REQ_AUDIO1_RX, // adc use the audio1 interface
31 .dst_addr_ctrl = DMA_ADDR_INCREMENT,
32 .src_addr_ctrl = DMA_ADDR_FIX,
33 .dstmode = DMA_NORMAL_MODE,
34 .srcmode = DMA_HANDSHAKE_MODE,
35 .dstwidth = DMA_CTR_WORD_WIDTH, // must word
36 .srcwidth = DMA_CTR_WORD_WIDTH, // must word
37 .src_burst_size = 0, // must 0
38 .read_num_en = 0,
39 .priority = 0,
40 .write_num_en = 0,
41 .auto_en = 0, // must 0
42 };
43 /**
44 * @brief This function serves to config adc_dma_chn channel.
45 * @param[in] chn - the DMA channel
46 * @return none
47 */
adc_set_dma_config(dma_chn_e chn)48 void adc_set_dma_config(dma_chn_e chn)
49 {
50 adc_dma_chn = chn;
51 dma_config(chn, &adc_rx_dma_config);
52 dma_clr_irq_mask(adc_dma_chn, TC_MASK | ERR_MASK | ABT_MASK);
53 dma_set_irq_mask(adc_dma_chn, TC_MASK);
54
55 audio_data_fifo1_path_sel(SAR_ADC_DATA_IN_FIFO, OUT_NO_USE); // connect DMA and ADC by audio input fifo1.
56 }
57 /**
58 * @brief This function serves to start sample with adc DMA channel.
59 * @param[in] adc_data_buf - the address of data buffer
60 * @param[in] data_byte_len - the length of data size by byte
61 * @return none
62 */
adc_start_sample_dma(unsigned short * adc_data_buf,unsigned int data_byte_len)63 void adc_start_sample_dma(unsigned short *adc_data_buf, unsigned int data_byte_len)
64 {
65 dma_set_address(adc_dma_chn, reg_fifo_buf_adr(1), (unsigned int)convert_ram_addr_cpu2bus(adc_data_buf));
66 dma_set_size(adc_dma_chn, data_byte_len, DMA_WORD_WIDTH);
67 dma_chn_en(adc_dma_chn);
68 adc_fifo_enable();
69 }
70 /**
71 * @brief This function serves to get adc DMA sample status.
72 * @return 0: the sample is in progress.
73 * !0: the sample is finished.
74 */
adc_get_sample_status_dma(void)75 unsigned char adc_get_sample_status_dma(void)
76 {
77 return (dma_get_tc_irq_status(1 << adc_dma_chn));
78 }
79 /**
80 * @brief This function serves to clear adc DMA sample status.
81 * @return none
82 */
adc_clr_sample_status_dma(void)83 void adc_clr_sample_status_dma(void)
84 {
85 dma_chn_dis(adc_dma_chn);
86 dma_clr_tc_irq_status(1 << adc_dma_chn);
87 }
88 /**
89 * @brief This function serves to stop adc DMA sample.
90 * @return none
91 * @attention function disable adc sample fifo, next sample should enable it.
92 */
adc_stop_sample_dma(void)93 void adc_stop_sample_dma(void)
94 {
95 adc_fifo_disable();
96 }
97 /**
98 * @brief This function is used to set IO port for ADC supply or ADC IO port voltage sampling.
99 * @param[in] mode - ADC gpio pin sample mode
100 * @param[in] pin - adc_input_pin_def_e ADC input gpio pin
101 * @return none
102 */
adc_pin_config(adc_input_pin_mode_e mode,adc_input_pin_def_e pin)103 void adc_pin_config(adc_input_pin_mode_e mode, adc_input_pin_def_e pin)
104 {
105 unsigned short adc_input_pin = pin & 0xfff;
106 switch (mode) {
107 case ADC_GPIO_MODE:
108 gpio_function_en(adc_input_pin);
109 gpio_input_dis(adc_input_pin);
110 gpio_output_dis(adc_input_pin);
111 gpio_set_low_level(adc_input_pin);
112 break;
113 case ADC_VBAT_MODE:
114 gpio_function_en(adc_input_pin);
115 gpio_input_dis(adc_input_pin);
116 gpio_output_en(adc_input_pin);
117 gpio_set_high_level(adc_input_pin);
118 break;
119 }
120 }
121 /**
122 * @brief This function is used to set two IO port configuration
123 * and set it as input channel of ADC difference IO port voltage sampling.
124 * @param[in] p_pin - enum variable of ADC analog positive input IO.
125 * @param[in] n_pin - enum variable of ADC analog negative input IO.
126 * @return none
127 */
adc_set_diff_pin(adc_input_pin_def_e p_pin,adc_input_pin_def_e n_pin)128 void adc_set_diff_pin(adc_input_pin_def_e p_pin, adc_input_pin_def_e n_pin)
129 {
130 adc_pin_config(ADC_GPIO_MODE, p_pin);
131 adc_pin_config(ADC_GPIO_MODE, n_pin);
132 adc_set_diff_input(p_pin >> 12, n_pin >> 12);
133 }
134 /**
135 * @brief This function serves to set the channel reference voltage.
136 * @param[in] v_ref - enum variable of ADC reference voltage.
137 * @return none
138 */
adc_set_ref_voltage(adc_ref_vol_e v_ref)139 void adc_set_ref_voltage(adc_ref_vol_e v_ref)
140 {
141 analog_write_reg8(areg_adc_vref, v_ref);
142 if (v_ref == ADC_VREF_1P2V) {
143 // Vref buffer bias current trimming: 150%
144 // Comparator preamp bias current trimming: 100%
145 analog_write_reg8(areg_ain_scale, (analog_read_reg8(areg_ain_scale) & (0xC0)) | 0x3d);
146 g_adc_vref = 1175;
147 } else if (v_ref == ADC_VREF_0P9V) {
148 // Vref buffer bias current trimming: 100%
149 // Comparator preamp bias current trimming: 100%
150 analog_write_reg8(areg_ain_scale, (analog_read_reg8(areg_ain_scale) & (0xC0)) | 0x15);
151 g_adc_vref = 900; // v_ref = ADC_VREF_0P9V,
152 }
153 }
154 /**
155 * @brief This function serves to set the sample frequency.
156 * @param[in] sample_freq - enum variable of ADC sample frequency.
157 * @return none
158 */
adc_set_sample_rate(adc_sample_freq_e sample_freq)159 void adc_set_sample_rate(adc_sample_freq_e sample_freq)
160 {
161 switch (sample_freq) {
162 case ADC_SAMPLE_FREQ_23K:
163 adc_set_state_length(1023, 15);
164 break;
165 case ADC_SAMPLE_FREQ_48K:
166 adc_set_state_length(490, 10);
167 break;
168 case ADC_SAMPLE_FREQ_96K:
169 adc_set_state_length(240, 10);
170 break;
171 }
172 }
173 /**
174 * @brief This function serves to set pre_scaling factor.
175 * @param[in] pre_scale - enum variable of ADC pre_scaling factor.
176 * @return none
177 */
adc_set_scale_factor(adc_pre_scale_e pre_scale)178 void adc_set_scale_factor(adc_pre_scale_e pre_scale)
179 {
180 analog_write_reg8(areg_ain_scale, (analog_read_reg8(areg_ain_scale) & (~FLD_SEL_AIN_SCALE)) | (pre_scale << 6));
181 g_adc_pre_scale = 1 << (unsigned char)pre_scale;
182 }
183 /**
184 * @brief This function serves to select Vbat voltage division factor
185 * @param[in] vbat_div - enum variable of Vbat division factor.
186 * @return none
187 */
adc_set_vbat_divider(adc_vbat_div_e vbat_div)188 void adc_set_vbat_divider(adc_vbat_div_e vbat_div)
189 {
190 analog_write_reg8(areg_adc_vref_vbat_div,
191 (analog_read_reg8(areg_adc_vref_vbat_div) & (~FLD_ADC_VREF_VBAT_DIV)) | (vbat_div << 2));
192 if (vbat_div) {
193 g_adc_vbat_divider = 5 - vbat_div;
194 } else {
195 g_adc_vbat_divider = 1;
196 }
197 }
198 /**
199 * @brief This function serves to ADC init.
200 * @param[in] v_ref - enum variable of ADC reference voltage.
201 * @param[in] pre_scale - enum variable of ADC pre_scaling factor.
202 * @param[in] sample_freq - enum variable of ADC sample frequency.
203 * @return none
204 * @attention Many features are configured in adc_init function. But some features
205 * such as adc_clk, resolution, tsample_cycle, we think better to set as default value,
206 * and user don't need to change them in most use cases.
207 */
adc_init(adc_ref_vol_e v_ref,adc_pre_scale_e pre_scale,adc_sample_freq_e sample_freq)208 void adc_init(adc_ref_vol_e v_ref, adc_pre_scale_e pre_scale, adc_sample_freq_e sample_freq)
209 {
210 adc_power_off(); // power off sar adc
211 adc_reset(); // reset whole digital adc module
212 adc_clk_en(); // enable signal of 24M clock to sar adc
213 adc_set_clk(5); // default adc_clk 4M = 24M/(1+div),
214 adc_set_ref_voltage(v_ref); // set channel Vref
215 adc_set_scale_factor(pre_scale); // set Analog input pre-scaling
216 adc_set_sample_rate(sample_freq); // set sample frequency.
217 adc_set_resolution(ADC_RES14); // default adc_resolution set as 14bit ,BIT(13) is sign bit
218 adc_set_tsample_cycle(ADC_SAMPLE_CYC_6); // 6 adc clocks for sample cycle
219 adc_set_m_chn_en(); // enable adc channel.
220 }
221 /**
222 * @brief This function serves to ADC gpio sample init.
223 * @param[in] pin - adc_input_pin_def_e ADC input gpio pin
224 * @param[in] v_ref - enum variable of ADC reference voltage.
225 * @param[in] pre_scale - enum variable of ADC pre_scaling factor.
226 * @param[in] sample_freq - enum variable of ADC sample frequency.
227 * @return none
228 * @attention gpio voltage sample suggested initial setting are Vref = 1.2V, pre_scale = 1/8.
229 * 0.9V Vref pre_scale must be 1.
230 * The sampling range are as follows:
231 * Vref pre_scale sampling range
232 * 1.2V 1 0 ~ 1.1V (suggest)
233 * 1.2V 1/8 0 ~ 3.5V (suggest)
234 * 0.9V 1 0 ~ 0.8V
235 */
adc_gpio_sample_init(adc_input_pin_def_e pin,adc_ref_vol_e v_ref,adc_pre_scale_e pre_scale,adc_sample_freq_e sample_freq)236 void adc_gpio_sample_init(adc_input_pin_def_e pin, adc_ref_vol_e v_ref, adc_pre_scale_e pre_scale,
237 adc_sample_freq_e sample_freq)
238 {
239 adc_init(v_ref, pre_scale, sample_freq);
240 adc_set_vbat_divider(ADC_VBAT_DIV_OFF);
241 adc_pin_config(ADC_GPIO_MODE, pin);
242 adc_set_diff_input(pin >> 12, GND);
243 }
244 /**
245 * @brief This function servers to initialized ADC temperature sensor.When the reference voltage is set to 1.2V, and
246 * at the same time, the division factor is set to 1 the most accurate.
247 * @return none.
248 * @attention Temperature sensor suggested initial setting are Vref = 1.2V, pre_scale = 1.
249 * The user don't need to change it.
250 */
adc_temperature_sample_init(void)251 void adc_temperature_sample_init(void)
252 {
253 adc_init(ADC_VREF_1P2V, ADC_PRESCALE_1, ADC_SAMPLE_FREQ_96K);
254 adc_set_diff_input(ADC_TEMSENSORP_EE, ADC_TEMSENSORN_EE);
255 adc_set_vbat_divider(ADC_VBAT_DIV_OFF);
256 adc_temp_sensor_power_on();
257 }
258
259 /**
260 * @brief This function servers to set ADC configuration for ADC supply voltage sampling.
261 * @return none
262 * @attention battery voltage sample suggested initial setting are Vref = 1.2V, pre_scale = 1, vbat_div = 1/3.
263 * Which has higher accuracy, user don't need to change it.
264 * The battery voltage sample range is 1.8~3.5V,
265 * and must set sys_init with the mode for battery voltage less than 3.6V.
266 * For battery voltage > 3.6V, should take some external voltage divider.
267 */
adc_battery_voltage_sample_init(void)268 void adc_battery_voltage_sample_init(void)
269 {
270 adc_init(ADC_VREF_1P2V, ADC_PRESCALE_1, ADC_SAMPLE_FREQ_96K);
271 adc_set_vbat_divider(ADC_VBAT_DIV_1F3);
272 adc_set_diff_input(ADC_VBAT, GND);
273 }
274 /**
275 * @brief This function serves to start adc sample and get raw adc sample code.
276 * @param[in] sample_buffer - pointer to the buffer adc sample code need to store.
277 * @param[in] sample_num - the number of adc sample code.
278 * @return none
279 */
adc_get_code_dma(unsigned short * sample_buffer,unsigned short sample_num)280 void adc_get_code_dma(unsigned short *sample_buffer, unsigned short sample_num)
281 {
282 /******start adc sample********/
283 adc_start_sample_dma((unsigned short *)sample_buffer, sample_num << 1);
284 /******wait for adc sample finish********/
285 while (!adc_get_sample_status_dma()) {
286 }
287 /******stop dma smaple********/
288 adc_stop_sample_dma();
289 /******clear adc sample finished status********/
290 adc_clr_sample_status_dma(); // must
291 /******get adc sample data and sort these data ********/
292 for (int i = 0; i < sample_num; i++) {
293 if (sample_buffer[i] &
294 BIT(13)) { // 14 bit resolution, BIT(13) is sign bit, 1 means negative voltage in differential_mode
295 sample_buffer[i] = 0;
296 } else {
297 sample_buffer[i] = (sample_buffer[i] & 0x1fff); // BIT(12..0) is valid adc code
298 }
299 }
300 }
301 /**
302 * @brief This function serves to directly get an adc sample code from analog registers.
303 * If you want to get the sampling results twice in succession,
304 * Must ensure that the sampling interval is more than 2 times the sampling period.
305 * @return adc_code - the adc sample code.
306 */
adc_get_code(void)307 unsigned short adc_get_code(void)
308 {
309 unsigned short adc_code;
310 /******Lock ADC code in analog register ********/
311 analog_write_reg8(areg_adc_data_sample_control,
312 analog_read_reg8(areg_adc_data_sample_control) | FLD_NOT_SAMPLE_ADC_DATA);
313 adc_code = analog_read_reg16(areg_adc_misc_l);
314 analog_write_reg8(areg_adc_data_sample_control,
315 analog_read_reg8(areg_adc_data_sample_control) & (~FLD_NOT_SAMPLE_ADC_DATA));
316
317 if (adc_code & BIT(13)) {
318 adc_code = 0;
319 } else {
320 adc_code &= 0x1FFF;
321 }
322 return adc_code;
323 }
324 /**
325 * @brief This function serves to calculate voltage from adc sample code.
326 * @param[in] adc_code - the adc sample code.
327 * @return adc_vol_mv - the average value of adc voltage value.
328 */
adc_calculate_voltage(unsigned short adc_code)329 unsigned short adc_calculate_voltage(unsigned short adc_code)
330 {
331 //////////////// adc sample data convert to voltage(mv) ////////////////
332 // (Vref, adc_pre_scale) (BIT<12~0> valid data)
333 // = adc_code * Vref * adc_pre_scale / 0x2000
334 // = adc_code * Vref * adc_pre_scale >>13
335 return ((adc_code * g_adc_vbat_divider * g_adc_pre_scale * g_adc_vref) >> 13);
336 }
337 /**
338 * @brief This function serves to calculate temperature from temperature sensor adc sample code.
339 * @param[in] adc_code - the temperature sensor adc sample code.
340 * @return adc_temp_value - the of temperature value.
341 * attention Temperature and adc_code are linearly related.
342 * We test four chips between -40~130 (Celsius) and got an average ratio:
343 * Temp = 564 - ((adc_code * 819)>>13),when Vref = 1.2V, pre_scale = 1.
344 */
adc_calculate_temperature(unsigned short adc_code)345 unsigned short adc_calculate_temperature(unsigned short adc_code)
346 {
347 //////////////// adc sample data convert to temperature(Celsius) ////////////////
348 // adc_temp_value = 564 - ((adc_code * 819)>>13)
349 return 564 - ((adc_code * 819) >> 13);
350 }
351