Mozzi  version 2016-12-11-17:03
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 //#include "mozzi_utils.h"
17 
18 // required from http://github.com/pedvide/ADC for Teensy 3.1
19 // This is a hacky way to access the ADC library, otherwise ADC.h has to be included at the top of every Arduino sketch.
20 /*#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO)
21 #include "../ADC/ADC_Module.cpp"
22 #include "../ADC/ADC.cpp"
23 #endif
24 */
25 
26 void setupFastAnalogRead(int8_t speed)
27 {
28 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
29 #else
30  if (speed == FAST_ADC){ // divide by 16
31  ADCSRA |= (1 << ADPS2);
32  ADCSRA &= ~(1 << ADPS1);
33  ADCSRA &= ~(1 << ADPS0);
34  } else if(speed == FASTER_ADC){ // divide by 8
35  ADCSRA &= ~(1 << ADPS2);
36  ADCSRA |= (1 << ADPS1);
37  ADCSRA |= (1 << ADPS0);
38  } else if(speed == FASTEST_ADC){ // divide by 4
39  ADCSRA &= ~(1 << ADPS2);
40  ADCSRA |= (1 << ADPS1);
41  ADCSRA &= ~(1 << ADPS0);
42  }
43 #endif
44 }
45 
46 
47 /*
48 void adcEnableInterrupt(){
49  ADCSRA |= (1 << ADIE);
50 }
51 */
52 
53 
54 void setupMozziADC(int8_t speed) {
55  #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
56  adc = new ADC();
57  adc->enableInterrupts(ADC_0);
58 #else
59  ADCSRA |= (1 << ADIE); // adc Enable Interrupt
60  setupFastAnalogRead(speed);
62 #endif
63 }
64 
65 
66 void disconnectDigitalIn(uint8_t channel_num){
67  #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
68 #else
69  DIDR0 |= 1<<channel_num;
70  #endif
71 }
72 
73 
74 void reconnectDigitalIn(uint8_t channel_num){
75  #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
76 #else
77  DIDR0 &= ~(1<<channel_num);
78  #endif
79 }
80 
81 
83  #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
84 #else
85  for (uint8_t i = 0; i<NUM_ANALOG_INPUTS; i++){
86  DIDR0 |= 1<<i;
87  }
88  #endif
89 }
90 
91 
93  #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
94 #else
95  for (uint8_t i = 0; i<NUM_ANALOG_INPUTS; i++){
96  DIDR0 &= ~(1<<i);
97  }
98  #endif
99 }
100 
101 
102 uint8_t adcPinToChannelNum(uint8_t pin) {
103 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
104 
105 #else
106 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
107  if (pin >= 54) pin -= 54; // allow for channel or pin numbers
108 #elif defined(__AVR_ATmega32U4__)
109  if (pin >= 18) pin -= 18; // allow for channel or pin numbers
110  pin = analogPinToChannel(pin); // moved from extra #if which was below in Arduino code, and redefined in mozzi_analog.h, with notes
111 #elif defined(__AVR_ATmega1284__)
112  if (pin >= 24) pin -= 24; // allow for channel or pin numbers
113 #else
114  if (pin >= 14) pin -= 14; // allow for channel or pin numbers
115 #endif
116  #endif
117  return pin;
118 }
119 
120 
121 // assumes channel is correct, not pin number, pin number would be converted first with adcPinToChannelNum
122 static void adcSetChannel(uint8_t channel) {
123 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
124 // ADC library converts pin/channel each time in startSingleRead
125 #else
126 #if defined(__AVR_ATmega32U4__)
127  ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((channel >> 3) & 0x01) << MUX5);
128 #elif defined(ADCSRB) && defined(MUX5)
129  // the MUX5 bit of ADCSRB selects whether we're reading from channels
130  // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
131  ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((channel >> 3) & 0x01) << MUX5);
132 #endif
133 
134  // set the analog reference (high two bits of ADMUX) and select the
135  // channel (low 4 bits). this also sets ADLAR (left-adjust result)
136  // to 0 (the default).
137 #if defined(ADMUX)
138  ADMUX = (1 << REFS0) | (channel & 0x07);
139 #endif
140 #endif
141 }
142 
143 
144 
145 
146 
147 // basically analogRead() chopped in half so the ADC conversion
148 // can be started here and received by another function.
149 void adcStartConversion(uint8_t channel) {
150 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
151  teensy_pin = channel; // remember for second startSingleRead
152  adc->startSingleRead(teensy_pin); // channel/pin gets converted every time in startSingleRead
153 #else
154  adcSetChannel(channel);
155 #if defined(ADCSRA) && defined(ADCL)
156  // start the conversion
157  ADCSRA |= (1 << ADSC);
158 #endif
159 #endif
160 }
161 
162 
163 
164 /*
165 The code below was informed initially by a discussion between
166 jRaskell, bobgardner, theusch, Koshchi, and code by jRaskell.
167 http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=789581
168 */
169 
170 
171 static volatile int analog_readings[NUM_ANALOG_INPUTS];
172 static Stack <volatile int8_t,NUM_ANALOG_INPUTS> adc_channels_to_read;
173 volatile static int8_t current_channel = -1; // volatile because accessed in control and adc ISRs
174 static bool first = true;
175 
176 
177 /* Called each time in updateControlWithAutoADC(), after updateControl()
178 */
179 void adcStartReadCycle(){
180  if (current_channel == -1) // last read of adc_channels_to_read stack was empty, ie. all channels from last time have been read
181  {
182 #if (USE_AUDIO_INPUT == true)
183  adc_channels_to_read.push(AUDIO_INPUT_PIN); // for audio
184 #else
185  adcReadSelectedChannels();
186  first = true;
187 #endif
188  }
189 }
190 
191 
192 
193 /* gets the next channel to read off the stack, and if there is a channel there, it changes to that channel and startsa conversion.
194 */
195 void adcReadSelectedChannels() {
196  current_channel = adc_channels_to_read.pop();
197  if(current_channel != -1) adcStartConversion(current_channel);
198 }
199 
200 
201 
202 int mozziAnalogRead(uint8_t pin) {
203 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
204 // ADC lib converts pin/channel in startSingleRead
205 #else
206  pin = adcPinToChannelNum(pin); // allow for channel or pin numbers
207 #endif
208  adc_channels_to_read.push(pin);
209  return analog_readings[pin];
210 }
211 
212 
213 /*
214 void receiveFirstControlADC(){
215  // do nothing
216 }
217 */
218 
219 
220 void startSecondControlADC() {
221 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
222  adc->startSingleRead(teensy_pin);
223 #else
224  ADCSRA |= (1 << ADSC); // start a second conversion on the current channel
225 #endif
226 }
227 
228 
229 void receiveSecondControlADC(){
230 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
231  analog_readings[current_channel] = adc->readSingle();
232 #else
233  analog_readings[current_channel] = ADC; // officially (ADCL | (ADCH << 8)) but the compiler works it out
234 #endif
235 }
236 
237 
238 /* This interrupt handler cycles through all analog inputs on the adc_channels_to_read Stack,
239 doing 2 conversions on each channel but only keeping the second conversion each time,
240 because the first conversion after changing channels is often inaccurate (on atmel-based arduinos).
241 
242 The version for USE_AUDIO_INPUT==true is in MozziGuts.cpp... compilation reasons...
243 */
244 #if(USE_AUDIO_INPUT==false)
245 #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(TEENSYDUINO) // teensy 3, 3.1
246 void adc0_isr(void)
247 #else
248 ISR(ADC_vect, ISR_BLOCK)
249 #endif
250 {
251  if (first)
252  {
253  //<1us
254  startSecondControlADC();
255  first=false;
256  }
257  else
258  {
259  // 3us
260  receiveSecondControlADC();
261  adcReadSelectedChannels();
262  first=true;
263  }
264 }
265 #endif
266 
A simple stack, used internally for keeping track of analog input channels as they are read...
Definition: Stack.h:18
T pop()
Get the item on top of the stack.
Definition: Stack.h:45
int mozziAnalogRead(uint8_t pin)
Reads the analog input of a chosen channel, without blocking other operations from running...
void adcReconnectAllDigitalIns()
Reconnect the digital input buffers for analog input channels which have been set for analog input wi...
void push(T item)
Put an item on the stack.
Definition: Stack.h:34
#define AUDIO_INPUT_PIN
This sets which analog input channel to use for audio input, if you have #define USE_AUDIO_INPUT true...
Definition: mozzi_config.h:83
void reconnectDigitalIn(uint8_t channel_num)
Reconnect the digital input buffer for an analog input channel which has been set for analog input wi...
void disconnectDigitalIn(uint8_t channel_num)
Prepare an analog input channel by turning off its digital input buffer.
void setupFastAnalogRead(int8_t speed)
This is automatically called in startMozzi.
void adcDisconnectAllDigitalIns()
Prepare all analog input channels by turning off their digital input buffers.