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 
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 
23 STM32ADC adc(ADC1);
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)
27 uint8_t adcPinToChannelNum(uint8_t pin) {
28  return pin;
29 }
30 
31 void adcStartConversion(uint8_t channel) {
32  stm32_current_adc_pin = channel;
33  adc.setPins(&stm32_current_adc_pin, 1);
34  adc.startConversion();
35 }
36 
37 static void startSecondADCReadOnCurrentChannel() {
38  adc.setPins(&stm32_current_adc_pin, 1);
39  adc.startConversion();
40 }
41 
42 void stm32_adc_eoc_handler() {
43  advanceADCStep();
44 }
45 
46 void setupMozziADC(int8_t speed) {
47  adc.attachInterrupt(stm32_adc_eoc_handler);
48 }
49 
50 
51 inline uint8_t STM32PinMap(uint8_t pin)
52 {
53  if (pin > 15) return pin-8;
54  else return pin;
55 }
56 
57 void setupFastAnalogRead(int8_t speed) {
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.)
59  if (speed == FASTEST_ADC) adc.setSampleRate(ADC_SMPR_1_5);
60  else if (speed == FASTER_ADC) adc.setSampleRate(ADC_SMPR_13_5);
61  else (adc.setSampleRate(ADC_SMPR_41_5));
62 }
63 #endif
64 
66 
67 
68 
70 #if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL_TIMED)
71 HardwareTimer audio_update_timer(MOZZI_AUDIO_UPDATE_TIMER);
72 #elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM)
73 HardwareTimer audio_update_timer(MOZZI_AUDIO_UPDATE_TIMER);
74 HardwareTimer audio_pwm_timer(MOZZI_AUDIO_PWM_TIMER);
75 
76 inline void audioOutput(const AudioOutput f) {
77 # if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_2PIN_PWM)
78  pwmWrite(MOZZI_AUDIO_PIN_1, (f.l()+MOZZI_AUDIO_BIAS) >> MOZZI_AUDIO_BITS_PER_CHANNEL);
79  pwmWrite(MOZZI_AUDIO_PIN_1_LOW, (f.l()+MOZZI_AUDIO_BIAS) & ((1 << MOZZI_AUDIO_BITS_PER_CHANNEL) - 1));
80 # else
81  pwmWrite(MOZZI_AUDIO_PIN_1, f.l()+MOZZI_AUDIO_BIAS);
82 # if (MOZZI_AUDIO_CHANNELS > 1)
83  pwmWrite(MOZZI_AUDIO_PIN_2, f.r()+MOZZI_AUDIO_BIAS);
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 
145 
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.
151  adc.enableInternalReading();
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 }
166 
167 } // namespace MozziPrivate
#define MOZZI_AUDIO_PIN_1
Only for MOZZI_AUDIO_MODE s MOZZI_OUTPUT_PWM and MOZZI_OUTPUT_2PIN_PWM: The IO pin to use as (first) ...
#define MOZZI_AUDIO_BITS_PER_CHANNEL
Only for MOZZI_AUDIO_MODE MOZZI_OUTPUT_2PIN_PWM.
#define MOZZI_AUDIO_RATE
Defines the audio rate, i.e.
void stopMozzi()
Stops audio and control interrupts and restores the timers to the values they had before Mozzi was st...
Definition: MozziGuts.hpp:303
Internal.
Definition: mozzi_rand_p.h:15
This struct encapsulates one frame of mono audio output.
Definition: AudioOutput.h:111