1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_ADC_H
8 #define _HARDWARE_ADC_H
9 
10 #include "pico.h"
11 #include "hardware/structs/adc.h"
12 #include "hardware/gpio.h"
13 
14 /** \file hardware/adc.h
15  *  \defgroup hardware_adc hardware_adc
16  *
17  * \brief Analog to Digital Converter (ADC) API
18  *
19  * RP-series microcontrollers have
20  *  an internal analogue-digital converter (ADC) with the following features:
21  * - SAR ADC
22  * - 500 kS/s (Using an independent 48MHz clock)
23  * - 12 bit (RP2040 8.7 ENOB, RP2350 9.2 ENOB)
24  * \if rp2040_specific
25  * - RP2040 5 input mux:
26  *  - 4 inputs that are available on package pins shared with GPIO[29:26]
27  *  - 1 input is dedicated to the internal temperature sensor
28  *  - 4 element receive sample FIFO
29  * \endif
30  *
31  * \if rp2350_specific
32  * - RP2350 5 or 9 input mux:
33  *  - 4 inputs available on QFN-60 package pins shared with GPIO[29:26]
34  *  - 8 inputs available on QFN-80 package pins shared with GPIO[47:40]
35  *  - 8 element receive sample FIFO
36  * \endif
37  * - One input dedicated to the internal temperature sensor (see Section 12.4.6)
38  * - Interrupt generation
39  * - DMA interface
40  *
41  * Although there is only one ADC you can specify the input to it using the adc_select_input() function.
42  * In round robin mode (adc_set_round_robin()), the ADC will use that input and move to the next one after a read.
43  *
44  * RP2040, RP2350 QFN-60: User ADC inputs are on 0-3 (GPIO 26-29), the temperature sensor is on input 4.
45  * RP2350 QFN-80 : User ADC inputs are on 0-7 (GPIO 40-47), the temperature sensor is on input 8.
46  *
47  * Temperature sensor values can be approximated in centigrade as:
48  *
49  * T = 27 - (ADC_Voltage - 0.706)/0.001721
50  *
51  * \subsection adc_example Example
52  * \addtogroup hardware_adc
53  *
54  * \include hello_adc.c
55  */
56 
57 // PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_ADC, Enable/disable assertions in the hardware_adc module, type=bool, default=0, group=hardware_adc
58 #ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_ADC
59 #ifdef PARAM_ASSERTIONS_ENABLED_ADC // backwards compatibility with SDK < 2.0.0
60 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_ADC PARAM_ASSERTIONS_ENABLED_ADC
61 #else
62 #define PARAM_ASSERTIONS_ENABLED_HARDWARE_ADC 0
63 #endif
64 #endif
65 
66 /**
67  * The ADC channel number of the on-board temperature sensor
68  */
69 #ifndef ADC_TEMPERATURE_CHANNEL_NUM
70 #define ADC_TEMPERATURE_CHANNEL_NUM (NUM_ADC_CHANNELS - 1)
71 #endif
72 
73 // PICO_CONFIG: PICO_ADC_CLKDIV_ROUND_NEAREST, True if floating point ADC clock divisors should be rounded to the nearest possible clock divisor rather than rounding down, type=bool, default=PICO_CLKDIV_ROUND_NEAREST, group=hardware_adc
74 #ifndef PICO_ADC_CLKDIV_ROUND_NEAREST
75 #define PICO_ADC_CLKDIV_ROUND_NEAREST PICO_CLKDIV_ROUND_NEAREST
76 #endif
77 
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
81 
82 /*! \brief  Initialise the ADC HW
83  *  \ingroup hardware_adc
84  *
85  */
86 void adc_init(void);
87 
88 /*! \brief  Initialise the gpio for use as an ADC pin
89  *  \ingroup hardware_adc
90  *
91  * Prepare a GPIO for use with ADC by disabling all digital functions.
92  *
93  * \param gpio The GPIO number to use. Allowable GPIO numbers are 26 to 29 inclusive on RP2040 or RP2350A, 40-48 inclusive on RP2350B
94  */
adc_gpio_init(uint gpio)95 static inline void adc_gpio_init(uint gpio) {
96     invalid_params_if(HARDWARE_ADC, gpio < ADC_BASE_PIN || gpio >= ADC_BASE_PIN + NUM_ADC_CHANNELS - 1);
97     // Select NULL function to make output driver hi-Z
98     gpio_set_function(gpio, GPIO_FUNC_NULL);
99     // Also disable digital pulls and digital receiver
100     gpio_disable_pulls(gpio);
101     gpio_set_input_enabled(gpio, false);
102 }
103 
104 /*! \brief  ADC input select
105  *  \ingroup hardware_adc
106  *
107  * Select an ADC input
108  * \if rp2040_specific
109  * On RP02040 0...3 are GPIOs 26...29 respectively. Input 4 is the onboard temperature sensor.
110  * \endif
111  * \if rp2350_specific
112  * On RP2350A 0...3 are GPIOs 26...29 respectively. Input 4 is the onboard temperature sensor.
113  * On RP2350B 0...7 are GPIOs 40...47 respectively. Input 8 is the onboard temperature sensor.
114  * \endif
115  *
116  * \param input Input to select.
117  */
adc_select_input(uint input)118 static inline void adc_select_input(uint input) {
119     valid_params_if(HARDWARE_ADC, input < NUM_ADC_CHANNELS);
120     hw_write_masked(&adc_hw->cs, input << ADC_CS_AINSEL_LSB, ADC_CS_AINSEL_BITS);
121 }
122 
123 /*! \brief  Get the currently selected ADC input channel
124  *  \ingroup hardware_adc
125  *
126  * \return The currently selected input channel.
127  *
128  * \if rp2040_specific
129  * On RP02040 0...3 are GPIOs 26...29 respectively. Input 4 is the onboard temperature sensor.
130  * \endif
131  *
132  * \if rp2350_specific
133  * On RP2350A 0...3 are GPIOs 26...29 respectively. Input 4 is the onboard temperature sensor.
134  * On RP2350B 0...7 are GPIOs 40...47 respectively. Input 8 is the onboard temperature sensor.
135  * \endif
136  */
adc_get_selected_input(void)137 static inline uint adc_get_selected_input(void) {
138     return (adc_hw->cs & ADC_CS_AINSEL_BITS) >> ADC_CS_AINSEL_LSB;
139 }
140 
141 /*! \brief  Round Robin sampling selector
142  *  \ingroup hardware_adc
143  *
144  * This function sets which inputs are to be run through in round robin mode.
145  * RP2040, RP2350 QFN-60: Value between 0 and 0x1f (bit 0 to bit 4 for GPIO 26 to 29 and temperature sensor input respectively)
146  * RP2350 QFN-80: Value between 0 and 0xff (bit 0 to bit 7 for GPIO 40 to 47 and temperature sensor input respectively)
147  *
148  * \param input_mask A bit pattern indicating which of the 5/8 inputs are to be sampled. Write a value of 0 to disable round robin sampling.
149  */
adc_set_round_robin(uint input_mask)150 static inline void adc_set_round_robin(uint input_mask) {
151     valid_params_if(HARDWARE_ADC, input_mask < (1 << NUM_ADC_CHANNELS));
152     hw_write_masked(&adc_hw->cs, input_mask << ADC_CS_RROBIN_LSB, ADC_CS_RROBIN_BITS);
153 }
154 
155 /*! \brief Enable the onboard temperature sensor
156  *  \ingroup hardware_adc
157  *
158  * \param enable Set true to power on the onboard temperature sensor, false to power off.
159  *
160  */
adc_set_temp_sensor_enabled(bool enable)161 static inline void adc_set_temp_sensor_enabled(bool enable) {
162     if (enable)
163         hw_set_bits(&adc_hw->cs, ADC_CS_TS_EN_BITS);
164     else
165         hw_clear_bits(&adc_hw->cs, ADC_CS_TS_EN_BITS);
166 }
167 
168 /*! \brief Perform a single conversion
169  *  \ingroup hardware_adc
170  *
171  *  Performs an ADC conversion, waits for the result, and then returns it.
172  *
173  * \return Result of the conversion.
174  */
pico_adc_read(void)175 static inline uint16_t pico_adc_read(void) {
176     hw_set_bits(&adc_hw->cs, ADC_CS_START_ONCE_BITS);
177 
178     while (!(adc_hw->cs & ADC_CS_READY_BITS))
179         tight_loop_contents();
180 
181     return (uint16_t) adc_hw->result;
182 }
183 
184 /*! \brief Enable or disable free-running sampling mode
185  *  \ingroup hardware_adc
186  *
187  * \param run false to disable, true to enable free running conversion mode.
188  */
adc_run(bool run)189 static inline void adc_run(bool run) {
190     if (run)
191         hw_set_bits(&adc_hw->cs, ADC_CS_START_MANY_BITS);
192     else
193         hw_clear_bits(&adc_hw->cs, ADC_CS_START_MANY_BITS);
194 }
195 
196 /*! \brief Set the ADC Clock divisor
197  *  \ingroup hardware_adc
198  *
199  * Period of samples will be (1 + div) cycles on average. Note it takes 96 cycles to perform a conversion,
200  * so any period less than that will be clamped to 96.
201  *
202  * \param clkdiv If non-zero, conversion will be started at intervals rather than back to back.
203  */
adc_set_clkdiv(float clkdiv)204 static inline void adc_set_clkdiv(float clkdiv) {
205     invalid_params_if(HARDWARE_ADC, clkdiv >= 1 << REG_FIELD_WIDTH(ADC_DIV_INT));
206     const int frac_bit_count = REG_FIELD_WIDTH(ADC_DIV_FRAC);
207 #if PICO_ADC_CLKDIV_ROUND_NEAREST
208     clkdiv += 0.5f / (1 << frac_bit_count); // round to the nearest fraction
209 #endif
210     adc_hw->div = (uint32_t)(clkdiv * (float) (1 << frac_bit_count));
211 }
212 
213 /*! \brief Setup the ADC FIFO
214  *  \ingroup hardware_adc
215  *
216  * \if rp2040_specific
217  * On RP2040 the FIFO is 4 samples long.
218  * \endif
219  *
220  * \if rp2350_specific
221  * On RP2350 the FIFO is 8 samples long.
222  * \endif
223  *
224  * If a conversion is completed and the FIFO is full, the result is dropped.
225  *
226  * \param en Enables write each conversion result to the FIFO
227  * \param dreq_en Enable DMA requests when FIFO contains data
228  * \param dreq_thresh Threshold for DMA requests/FIFO IRQ if enabled.
229  * \param err_in_fifo If enabled, bit 15 of the FIFO contains error flag for each sample
230  * \param byte_shift Shift FIFO contents to be one byte in size (for byte DMA) - enables DMA to byte buffers.
231  */
adc_fifo_setup(bool en,bool dreq_en,uint16_t dreq_thresh,bool err_in_fifo,bool byte_shift)232  static inline void adc_fifo_setup(bool en, bool dreq_en, uint16_t dreq_thresh, bool err_in_fifo, bool byte_shift) {
233     hw_write_masked(&adc_hw->fcs,
234                    (bool_to_bit(en) << ADC_FCS_EN_LSB) |
235                    (bool_to_bit(dreq_en) << ADC_FCS_DREQ_EN_LSB) |
236                    (((uint)dreq_thresh) << ADC_FCS_THRESH_LSB) |
237                    (bool_to_bit(err_in_fifo) << ADC_FCS_ERR_LSB) |
238                    (bool_to_bit(byte_shift) << ADC_FCS_SHIFT_LSB),
239                    ADC_FCS_EN_BITS |
240                    ADC_FCS_DREQ_EN_BITS |
241                    ADC_FCS_THRESH_BITS |
242                    ADC_FCS_ERR_BITS |
243                    ADC_FCS_SHIFT_BITS
244     );
245 }
246 
247 /*! \brief Check FIFO empty state
248  *  \ingroup hardware_adc
249  *
250  * \return Returns true if the FIFO is empty
251  */
adc_fifo_is_empty(void)252 static inline bool adc_fifo_is_empty(void) {
253     return adc_hw->fcs & ADC_FCS_EMPTY_BITS;
254 }
255 
256 /*! \brief Get number of entries in the ADC FIFO
257  *  \ingroup hardware_adc
258  *
259  * \if rp2040_specific
260  * On RP2040 the FIFO is 4 samples long.
261  * \endif
262  * \if rp2350_specific
263  * On RP2350 the FIFO is 8 samples long.
264  * \endif
265  *
266  * This function will return how many samples are currently present.
267  */
adc_fifo_get_level(void)268 static inline uint8_t adc_fifo_get_level(void) {
269     return (adc_hw->fcs & ADC_FCS_LEVEL_BITS) >> ADC_FCS_LEVEL_LSB;
270 }
271 
272 /*! \brief Get ADC result from FIFO
273  *  \ingroup hardware_adc
274  *
275  * Pops the latest result from the ADC FIFO.
276  */
adc_fifo_get(void)277 static inline uint16_t adc_fifo_get(void) {
278     return (uint16_t)adc_hw->fifo;
279 }
280 
281 /*! \brief Wait for the ADC FIFO to have data.
282  *  \ingroup hardware_adc
283  *
284  * Blocks until data is present in the FIFO
285  */
adc_fifo_get_blocking(void)286 static inline uint16_t adc_fifo_get_blocking(void) {
287     while (adc_fifo_is_empty())
288         tight_loop_contents();
289     return (uint16_t)adc_hw->fifo;
290 }
291 
292 /*! \brief Drain the ADC FIFO
293  *  \ingroup hardware_adc
294  *
295  * Will wait for any conversion to complete then drain the FIFO, discarding any results.
296  */
adc_fifo_drain(void)297 static inline void adc_fifo_drain(void) {
298     // Potentially there is still a conversion in progress -- wait for this to complete before draining
299     while (!(adc_hw->cs & ADC_CS_READY_BITS))
300         tight_loop_contents();
301     while (!adc_fifo_is_empty())
302         (void) adc_fifo_get();
303 }
304 
305 /*! \brief Enable/Disable ADC interrupts.
306  *  \ingroup hardware_adc
307  *
308  * \param enabled Set to true to enable the ADC interrupts, false to disable
309  */
adc_irq_set_enabled(bool enabled)310 static inline void adc_irq_set_enabled(bool enabled) {
311     adc_hw->inte = !!enabled;
312 }
313 
314 #ifdef __cplusplus
315 }
316 #endif
317 
318 #endif
319