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