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 
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 
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
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...
#define IS_STM32()
void reconnectDigitalIn(uint8_t channel_num)
Reconnect the digital input buffer for an analog input channel which has been set for analog input wi...
#define IS_AVR()
#define IS_TEENSY3()
void disconnectDigitalIn(uint8_t channel_num)
Prepare an analog input channel by turning off its digital input buffer.
void setupFastAnalogRead(int8_t speed=FAST_ADC)
This is automatically called in startMozzi.
void adcDisconnectAllDigitalIns()
Prepare all analog input channels by turning off their digital input buffers.
#define IS_ESP8266()
#define IS_ESP32()