Mozzi  version v2.0
sound synthesis library for Arduino
MozziGuts_impl_STM32.hpp
1 /*
2  * MozziGuts_impl_STM32.hpp
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2020-2024 Thomas Friedrichsmeier 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 #include "HardwareTimer.h"
13 
14 namespace MozziPrivate {
15 
16 ////// BEGIN analog input code ////////
17 #if MOZZI_IS(MOZZI_ANALOG_READ, MOZZI_ANALOG_READ_STANDARD)
18 
19 } // namespace MozziPrivate
20 //#include <STM32ADC.h> // Disabled, here. See hardware_defines.h
21 namespace MozziPrivate {
22 
24 uint8_t stm32_current_adc_pin; // TODO: this is actually a "channel" according to our terminology, but "channel" and "pin" are equal on this platform
25 #define getADCReading() adc.getData()
26 #define channelNumToIndex(channel) STM32PinMap(channel)
28  return pin;
29 }
30 
35 }
36 
40 }
41 
42 void stm32_adc_eoc_handler() {
44 }
45 
48 }
49 
50 
52 {
53  if (pin > 15) return pin-8;
54  else return pin;
55 }
56 
58  // 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.)
62 }
63 #endif
64 
65 ////// END analog input code ////////
66 
67 
68 
69 //// BEGIN AUDIO OUTPUT code ///////
70 #if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL_TIMED)
72 #elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM)
75 
76 inline void audioOutput(const AudioOutput f) {
77 # if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_2PIN_PWM)
80 # else
82 # if (MOZZI_AUDIO_CHANNELS > 1)
84 # endif
85 #endif
86 }
87 #endif
88 
89 static void startAudio() {
90 #if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM, MOZZI_OUTPUT_EXTERNAL_TIMED)
91  audio_update_timer.pause();
92  //audio_update_timer.setPeriod(1000000UL / MOZZI_AUDIO_RATE);
93  // Manually calculate prescaler and overflow instead of using setPeriod, to avoid rounding errors
94  uint32_t period_cyc = F_CPU / MOZZI_AUDIO_RATE;
95  uint16_t prescaler = (uint16_t)(period_cyc / 65535 + 1);
96  uint16_t overflow = (uint16_t)((period_cyc + (prescaler / 2)) / prescaler);
97  audio_update_timer.setPrescaleFactor(prescaler);
98  audio_update_timer.setOverflow(overflow);
99  audio_update_timer.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
100  audio_update_timer.setCompare(TIMER_CH1,
101  1); // Interrupt 1 count after each update
102  audio_update_timer.attachInterrupt(TIMER_CH1, defaultAudioOutput);
103  audio_update_timer.refresh();
104  audio_update_timer.resume();
105 #endif
106 
107 #if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM)
108  pinMode(MOZZI_AUDIO_PIN_1, PWM);
109 # if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_2PIN_PWM)
110  pinMode(MOZZI_AUDIO_PIN_1_LOW, PWM);
111 # elif (MOZZI_AUDIO_CHANNELS > 1)
112  pinMode(MOZZI_AUDIO_PIN_2, PWM);
113 # endif
114 
115 # define MAX_CARRIER_FREQ (F_CPU / (1 << MOZZI_AUDIO_BITS_PER_CHANNEL))
116 # if MAX_CARRIER_FREQ < MOZZI_AUDIO_RATE
117 # error Configured audio resolution is definitely too high at the configured audio rate (and the given CPU speed)
118 # elif MAX_CARRIER_FREQ < (MOZZI_AUDIO_RATE * 3)
119 # warning Configured audio resolution may be higher than optimal at the configured audio rate (and the given CPU speed)
120 # endif
121 
122 # if MAX_CARRIER_FREQ < (MOZZI_AUDIO_RATE * 5)
123  // Generate as fast a carrier as possible
124  audio_pwm_timer.setPrescaleFactor(1);
125 # else
126  // No point in generating arbitrarily high carrier frequencies. In fact, if
127  // there _is_ any headroom, give the PWM pin more time to swing from HIGH to
128  // LOW and BACK, cleanly
129  audio_pwm_timer.setPrescaleFactor((int)MAX_CARRIER_FREQ / (MOZZI_AUDIO_RATE * 5));
130 # endif
131  audio_pwm_timer.setOverflow(
132  1 << MOZZI_AUDIO_BITS_PER_CHANNEL); // Allocate enough room to write all
133  // intended bits
134 # undef MAX_CARRIER_FREQ // no longer needed
135 #endif
136 }
137 
138 void stopMozzi() {
139 #if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM, MOZZI_OUTPUT_EXTERNAL_TIMED)
140  audio_update_timer.pause();
141 #endif
142 }
143 
144 //// END AUDIO OUTPUT code ///////
145 
146 //// BEGIN Random seeding ////////
147 void MozziRandPrivate::autoSeed() {
148  // Unfortunately the internal temp sensor on STM32s does _not_ appear to create a lot of noise.
149  // Ironically, the calls to calibrate help induce some random noise. You're still fairly likely to produce two equal
150  // random seeds in two subsequent runs, however.
152  union {
153  float cf;
154  uint32_t ci;
155  } conv;
156  conv.cf = adc.readTemp();
157  x=x^conv.ci;
158  adc.calibrate();
159  conv.cf = adc.readTemp();
160  y=y^conv.ci;
161  adc.calibrate();
162  conv.cf = adc.readTemp();
163  z=z^conv.ci;
164 }
165 //// END Random seeding ////////
166 
167 } // namespace MozziPrivate