Mozzi  version v2.0
sound synthesis library for Arduino
mozzi_analog.h
1 /*
2  * mozzi_analog.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2012-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 
13 #ifndef MOZZI_ANALOG_H_
14 #define MOZZI_ANALOG_H_
15 
16 #include "Arduino.h"
17 
18 #include "hardware_defines.h"
19 
20 // for setupFastAnalogRead()
21 enum ANALOG_READ_SPEED {FAST_ADC,FASTER_ADC,FASTEST_ADC};
22 
23 /** @defgroup analog
24 
25 @brief Efficient analog input functions for sensors and audio.
26 
27 Helps produce glitch-free audio by allowing analog input functions which normally block processing to be performed in the background.
28 */
29 
30 /**
31 @ingroup analog
32 This is automatically called in startMozzi.
33 It makes mozziAnalogRead() happen faster than the standard Arduino analogRead(), changing the
34 duration from about 105 in unmodified Arduino to about 16 microseconds for a
35 dependable read with the default speed parameter FAST_ADC.
36 If you want to set on of the faster modes (see params) you can call this after startMozzi().
37 See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1208715493/11, and
38 http://www.marulaberry.co.za/index.php/tutorials/code/arduino-adc/
39 @param speed FAST_ADC, FASTER_ADC or FASTEST_ADC. If no parameter is supplied, the
40 default is FAST_ADC, which sets the analog conversion clock predivide rate to
41 16, giving 1Mhz on a 16MHz board, the fastest rate for which behaviour is
42 defined (~16us per sample). However, divisors of 8 and 4 also show usable
43 results in the graphs in this paper:
44 http://dam.mellis.org/Mellis%20-%20Sensor%20Library%20for%20Arduino%20-%20Paper.pdf,
45 so you can also try FASTER_ADC or FASTEST_ADC for divide rates of 8 or 4, giving
46 times of about 8us or 4us per sample. Beware, reliable results will depend on
47 the sort of input signal you have. Only use FASTER_ADC or FASTEST_ADC if you
48 know what you're doing.
49 */
50 void setupFastAnalogRead(int8_t speed=FAST_ADC);
51 
52 
53 
54 /* @ingroup analog
55 Set up for asynchronous analog input, which enables analog reads to take
56 place in the background without blocking the processor.
57 @param speed FAST_ADC, FASTER_ADC or FASTEST_ADC. See setupFastAnalogRead();
58 */
59 void setupMozziADC(int8_t speed=FAST_ADC);
60 
61 
62 
63 /** @ingroup analog
64 Prepare an analog input channel by turning off its digital input buffer.
65 This helps to reduce noise, increase analog reading speed, and save power.
66 
67 Here's more detail from http://www.openmusiclabs.com/learning/digital/atmega-adc/:
68 
69 The DIDR (Data Input Disable Register) disconnects the digital inputs from
70 whichever ADC channels you are using. This is important for 2 reasons. First
71 off, an analog input will be floating all over the place, and causing the
72 digital input to constantly toggle high and low. This creates excessive noise
73 near the ADC, and burns extra power. Secondly, the digital input and associated
74 DIDR switch have a capacitance associated with them which will slow down your
75 input signal if you are sampling a highly resistive load.
76 
77 And from the ATmega328p datasheet, p266:
78 
79 When an analog signal is applied to the ADC pin and the digital input from
80 this pin is not needed, this bit should be written logic one to reduce power
81 consumption in the digital input buffer. Note that ADC named_pins ADC7
82 and ADC6 do not have digital input buffers, and therefore do not require
83 Digital Input Disable bits.
84 @param channel_num the analog input channel you wish to use.
85 */
86 inline void disconnectDigitalIn(uint8_t channel_num) {
87 #if IS_AVR()
88  DIDR0 |= 1<<channel_num;
89 #else
90  (void) channel_num; // unused, suppress warning
91 #endif
92 }
93 
94 /** @ingroup analog
95 Reconnect the digital input buffer for an analog input channel which has
96 been set for analog input with disconnectDigitalIn().
97 @param channel_num the analog input channel you wish to reconnect.
98 */
99 inline void reconnectDigitalIn(uint8_t channel_num) {
100 #if IS_AVR()
101  DIDR0 &= ~(1<<channel_num);
102 #else
103  (void) channel_num; // unused, suppress warning
104 #endif
105 }
106 
107 /** @ingroup analog
108 Prepare all analog input channels by turning off their digital input buffers.
109 This helps to reduce noise, increase analog reading speed, and save power.
110 */
111 inline void adcDisconnectAllDigitalIns() {
112 #if IS_AVR()
113  for (uint8_t i = 0; i<NUM_ANALOG_INPUTS; i++){
114  DIDR0 |= 1<<i;
115  }
116 #endif
117 }
118 
119 
120 /** @ingroup analog
121 Reconnect the digital input buffers for analog input channels which have
122 been set for analog input with disconnectDigitalIn().
123 */
124 inline void adcReconnectAllDigitalIns() {
125 #if IS_AVR()
126  for (uint8_t i = 0; i<NUM_ANALOG_INPUTS; i++){
127  DIDR0 &= ~(1<<i);
128  }
129 #endif
130 }
131 
132 /* @ingroup analog
133 Starts an analog to digital conversion of the voltage on a specified channel. Unlike
134 Arduino's analogRead() function which waits until a conversion is complete before
135 returning, adcStartConversion() only sets the conversion to begin, so you can use
136 the cpu for other things and call for the result later with adcGetResult().
137 @param channel is the analog channel number (0 to ....), which is not necessarily the same as the pin number
138 Use adcPinToChannelNum() to convert the pin number to its channel number.
139 @note Timing: about 1us when used in updateControl() with MOZZI_CONTROL_RATE 64.
140 */
141 void adcStartConversion(uint8_t channel);
142 
143 /** @ingroup analog
144 See mozziAnalogRead(). The template parameter RES specifies the number of bits to return.
145 */
146 template<byte RES> uint16_t mozziAnalogRead(uint8_t pin);
147 
148 /** @ingroup analog
149 See mozziAnalogRead() but always returns the value shifted to 16 bit range. THis is exactly
150 equivalent to mozziAnalogRead<16>(pin);
151 */
152 inline uint16_t mozziAnalogRead16(uint8_t pin) { return mozziAnalogRead<16>(pin); };
153 
154 #if defined(FOR_DOXYGEN_ONLY) || defined(MOZZI_ANALOG_READ_RESOLUTION)
155 /** @ingroup analog
156 Reads the analog input of a chosen channel, without blocking other operations from running.
157 It actually returns the most recent analog reading and puts the chosen pin or channel
158 on the stack of channels to be read in the background before the next control
159 interrupt.
160 
161 @note Analog reads have different hardware resolution on different platforms. E.g. an analog read
162  on an Arduino Uno R3 will return a value in the range 0-1023 (10 bits), on a Raspberry Pi Pico
163  it will return 0-4095 (12 bits). For portable code, it is thus necessary to specify the desired
164  resolution of reads. This can be done by setting MOZZI_ANALOG_READ_RESOLUTION to the resolution
165  in bits, near the top of your sketch. All reads will then be adjusted to that range, automatically
166  (using a simple bit-shift). Alternatively, the templated version of mozziAanalogRead() allows
167  to specifiy the target resolution per read.
168  If MOZZI_ANALOG_READ_RESOLUTION is not defined, this (non-templated) function returns a value
169  in the default hardware resolution, with a warning.
170 
171 @param pin_or_channel the analog pin or channel number.
172 @return the digitised value of the voltage on the chosen channel. See the note above regarding the output range!
173 */
174 inline uint16_t mozziAnalogRead(uint8_t pin) { return mozziAnalogRead<MOZZI_ANALOG_READ_RESOLUTION>(pin); }
175 #else
176 MOZZI_DEPRECATED("2.0", "This use of mozziAnalogRead() is not portable. Refer to the API documentation for suggested alternatives.") inline uint16_t mozziAnalogRead(uint8_t pin) { return mozziAnalogRead<MOZZI__INTERNAL_ANALOG_READ_RESOLUTION>(pin); }
177 #endif
178 
179 uint8_t adcPinToChannelNum(uint8_t pin);
180 
181 
182 #endif /* MOZZI_ANALOG_H_ */