| Mozzi version v1.1.0 sound synthesis library for Arduino |

mozzi_analog.cpp
1 /*
2 * mozzi_analog.cpp
3 *
4 * Copyright 2012 Tim Barrass.
5 *
6 * This file is part of Mozzi.
7 *
8 * Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
9 *
10 */
11
12
13 #include "mozzi_config.h"
14 #include "mozzi_analog.h"
15 #include "Stack.h"
16
17 //#include "mozzi_utils.h"
18
19 #include "hardware_defines.h"
20 #if IS_TEENSY3()
21 // required from http://github.com/pedvide/ADC for Teensy 3.*
22 #include <ADC.h>
23 #elif IS_STM32()
24 //#include <STM32ADC.h>
25 #endif
26
27 // defined in Mozziguts.cpp
28 #if IS_TEENSY3()
29 extern ADC *adc; // adc object
30 extern uint8_t teensy_pin;
31 #elif IS_STM32()
32 extern STM32ADC adc;
33 extern uint8_t stm32_current_adc_pin;
34 void stm32_adc_eoc_handler();
35 #endif
36
37 extern uint8_t analog_reference;
38
39 void setupFastAnalogRead(int8_t speed)
40 {
41 #if IS_AVR()
42 if (speed == FAST_ADC){ // divide by 16
43 ADCSRA |= (1 << ADPS2);
44 ADCSRA &= ~(1 << ADPS1);
45 ADCSRA &= ~(1 << ADPS0);
46 } else if(speed == FASTER_ADC){ // divide by 8
47 ADCSRA &= ~(1 << ADPS2);
48 ADCSRA |= (1 << ADPS1);
49 ADCSRA |= (1 << ADPS0);
50 } else if(speed == FASTEST_ADC){ // divide by 4
51 ADCSRA &= ~(1 << ADPS2);
52 ADCSRA |= (1 << ADPS1);
53 ADCSRA &= ~(1 << ADPS0);
54 }
55 #elif IS_STM32()
56 // NOTE: These picks are pretty arbitrary. Further available options are 7_5, 28_5, 55_5, 71_5 and 239_5 (i.e. 7.5 ADC cylces, etc.)
57 if (speed == FASTEST_ADC) adc.setSampleRate(ADC_SMPR_1_5);
58 else if (speed == FASTER_ADC) adc.setSampleRate(ADC_SMPR_13_5);
59 else (adc.setSampleRate(ADC_SMPR_41_5));
60 #endif
61 }
62
63
64 /*
65 void adcEnableInterrupt(){
66 ADCSRA |= (1 << ADIE);
67 }
68 */
69
70
71 void setupMozziADC(int8_t speed) {
72 #if IS_TEENSY3()
73 adc = new ADC();
74 adc->enableInterrupts(ADC_0);
75 #elif IS_STM32()
76 adc.calibrate();
77 setupFastAnalogRead(speed);
78 adc.attachInterrupt(stm32_adc_eoc_handler, ADC_EOC);
79 #elif IS_AVR()
80 ADCSRA |= (1 << ADIE); // adc Enable Interrupt
81 setupFastAnalogRead(speed);
82 adcDisconnectAllDigitalIns();
83 #else
84 #warning Fast ADC not implemented on this platform
85 #endif
86 }
87
88
89 void disconnectDigitalIn(uint8_t channel_num){
90 #if IS_AVR()
91 DIDR0 |= 1<<channel_num;
92 #endif
93 }
94
95
96 void reconnectDigitalIn(uint8_t channel_num){
97 #if IS_AVR()
98 DIDR0 &= ~(1<<channel_num);
99 #endif
100 }
101
102
103 void adcDisconnectAllDigitalIns(){
104 #if IS_AVR()
105 for (uint8_t i = 0; i<NUM_ANALOG_INPUTS; i++){
106 DIDR0 |= 1<<i;
107 }
108 #endif
109 }
110
111
112 void adcReconnectAllDigitalIns(){
113 #if IS_AVR()
114 for (uint8_t i = 0; i<NUM_ANALOG_INPUTS; i++){
115 DIDR0 &= ~(1<<i);
116 }
117 #endif
118 }
119
120
121 uint8_t adcPinToChannelNum(uint8_t pin) {
122
123 #if IS_AVR()
124 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
125 if (pin >= 54) pin -= 54; // allow for channel or pin numbers
126 #elif defined(__AVR_ATmega32U4__)
127 if (pin >= 18) pin -= 18; // allow for channel or pin numbers
128 pin = analogPinToChannel(pin); // moved from extra #if which was below in Arduino code, and redefined in mozzi_analog.h, with notes
129 #elif defined(__AVR_ATmega1284__)
130 if (pin >= 24) pin -= 24; // allow for channel or pin numbers
131 #else
132 if (pin >= 14) pin -= 14; // allow for channel or pin numbers
133 #endif
134 #endif
135 return pin;
136 }
137
138
139 // assumes channel is correct, not pin number, pin number would be converted first with adcPinToChannelNum
140 static void adcSetChannel(uint8_t channel) {
141 #if IS_AVR()
142 #if defined(__AVR_ATmega32U4__)
143 ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((channel >> 3) & 0x01) << MUX5);
144 #elif defined(ADCSRB) && defined(MUX5)
145 // the MUX5 bit of ADCSRB selects whether we're reading from channels
146 // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
147 ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((channel >> 3) & 0x01) << MUX5);
148 #endif
149
150 // from wiring_analog.c:
151 // set the analog reference (high two bits of ADMUX) and select the
152 // channel (low 4 bits). this also sets ADLAR (left-adjust result)
153 // to 0 (the default).
154 #if defined(ADMUX)
155 #if defined(TEENSYDUINO) // analog_reference is not part TEENSY 2.0 codebase
156 ADMUX = (1 << REFS0) | (channel & 0x07); // TB2017 this overwrote analog_reference
157 #else
158 ADMUX = (analog_reference << 6) | (channel & 0x07);
159 #endif
160 #endif
161 #else
162 // For other platforms ADC library converts pin/channel each time in startSingleRead
163 #endif
164 }
165
166
167
168
169
170 // basically analogRead() chopped in half so the ADC conversion
171 // can be started here and received by another function.
172 void adcStartConversion(uint8_t channel) {
173 #if IS_TEENSY3()
174 teensy_pin = channel; // remember for second startSingleRead
175 adc->startSingleRead(teensy_pin); // channel/pin gets converted every time in startSingleRead
176 #elif IS_STM32()
177 stm32_current_adc_pin = channel;
178 adc.setPins(&stm32_current_adc_pin, 1);
179 adc.startConversion();
180 #elif IS_AVR()
181 adcSetChannel(channel);
182 #if defined(ADCSRA) && defined(ADCL)
183 // start the conversion
184 ADCSRA |= (1 << ADSC);
185 #endif
186 #else
187 #warning Fast analog read not implemented on this platform
188 #endif
189 }
190
191
192
193 /*
194 The code below was informed initially by a discussion between
195 jRaskell, bobgardner, theusch, Koshchi, and code by jRaskell.
196 http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=789581
197 */
198
199 static volatile int analog_readings[NUM_ANALOG_INPUTS];
200 static Stack <volatile int8_t,NUM_ANALOG_INPUTS> adc_channels_to_read;
201 volatile static int8_t current_channel = -1; // volatile because accessed in control and adc ISRs
202 static bool first = true;
203
204 /* Called each time in updateControlWithAutoADC(), after updateControl()
205 */
206 void adcStartReadCycle(){
207 if (current_channel == -1) // last read of adc_channels_to_read stack was empty, ie. all channels from last time have been read
208 {
209 #if (USE_AUDIO_INPUT == true)
210 adc_channels_to_read.push(AUDIO_INPUT_PIN); // for audio
211 #else
212 adcReadSelectedChannels();
213 first = true;
214 #endif
215 }
216 }
217
218
219
220 /* gets the next channel to read off the stack, and if there is a channel there, it changes to that channel and startsa conversion.
221 */
222 void adcReadSelectedChannels() {
223 current_channel = adc_channels_to_read.pop();
224 if(current_channel != -1) adcStartConversion(current_channel);
225 }
226
227
228
229 int mozziAnalogRead(uint8_t pin) {
230 #if IS_ESP8266() || IS_ESP32()
231 #warning Asynchronouos analog reads not implemented for this platform
232 return analogRead(pin);
233 #else
234 // ADC lib converts pin/channel in startSingleRead
235 #if IS_AVR()
236 pin = adcPinToChannelNum(pin); // allow for channel or pin numbers
237 #endif
238 adc_channels_to_read.push(pin);
239 return analog_readings[pin];
240 #endif
241 }
242
243
244 /*
245 void receiveFirstControlADC(){
246 // do nothing
247 }
248 */
249
250
251 void startSecondControlADC() {
252 #if IS_TEENSY3()
253 adc->startSingleRead(teensy_pin);
254 #elif IS_STM32()
255 adc.setPins(&stm32_current_adc_pin, 1);
256 adc.startConversion();
257 #elif IS_AVR()
258 ADCSRA |= (1 << ADSC); // start a second conversion on the current channel
259 #endif
260 }
261
262
263 void receiveSecondControlADC(){
264 #if IS_TEENSY3()
265 analog_readings[current_channel] = adc->readSingle();
266 #elif IS_STM32()
267 analog_readings[current_channel] = adc.getData();
268 #elif IS_AVR()
269 analog_readings[current_channel] = ADC; // officially (ADCL | (ADCH << 8)) but the compiler works it out
270 #endif
271 }
272
273
274 /* This interrupt handler cycles through all analog inputs on the adc_channels_to_read Stack,
275 doing 2 conversions on each channel but only keeping the second conversion each time,
276 because the first conversion after changing channels is often inaccurate (on atmel-based arduinos).
277
278 The version for USE_AUDIO_INPUT==true is in MozziGuts.cpp... compilation reasons...
279 */
280 #if(USE_AUDIO_INPUT==false)
281 #if IS_TEENSY3()
282 void adc0_isr(void)
283 #elif IS_STM32()
284 void stm32_adc_eoc_handler()
285 #elif IS_AVR()
286 ISR(ADC_vect, ISR_BLOCK)
287 #endif
288 #if IS_TEENSY3() || IS_STM32() || IS_AVR()
289 {
290 if (first)
291 {
292 //<1us
293 startSecondControlADC();
294 first=false;
295 }
296 else
297 {
298 // 3us
299 receiveSecondControlADC();
300 adcReadSelectedChannels();
301 first=true;
302 }
303 }
304 #endif
305 #endif
mozziAnalogRead
int mozziAnalogRead(uint8_t pin)
Reads the analog input of a chosen channel, without blocking other operations from running...
Definition: mozzi_analog.cpp:229
adcReconnectAllDigitalIns
void adcReconnectAllDigitalIns()
Reconnect the digital input buffers for analog input channels which have been set for analog input wi...
Definition: mozzi_analog.cpp:112
IS_STM32
#define IS_STM32()
Definition: hardware_defines.h:18
reconnectDigitalIn
void reconnectDigitalIn(uint8_t channel_num)
Reconnect the digital input buffer for an analog input channel which has been set for analog input wi...
Definition: mozzi_analog.cpp:96
IS_AVR
#define IS_AVR()
Definition: hardware_defines.h:15
IS_TEENSY3
#define IS_TEENSY3()
Definition: hardware_defines.h:17
disconnectDigitalIn
void disconnectDigitalIn(uint8_t channel_num)
Prepare an analog input channel by turning off its digital input buffer.
Definition: mozzi_analog.cpp:89
setupFastAnalogRead
void setupFastAnalogRead(int8_t speed=FAST_ADC)
This is automatically called in startMozzi.
Definition: mozzi_analog.cpp:39
adcDisconnectAllDigitalIns
void adcDisconnectAllDigitalIns()
Prepare all analog input channels by turning off their digital input buffers.
Definition: mozzi_analog.cpp:103
IS_ESP8266
#define IS_ESP8266()
Definition: hardware_defines.h:19
IS_ESP32
#define IS_ESP32()
Definition: hardware_defines.h:20