Skip to content

Commit

Permalink
De-duplicate documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
tfry-git committed Nov 19, 2023
1 parent 219980e commit 5b946e0
Show file tree
Hide file tree
Showing 11 changed files with 437 additions and 562 deletions.
451 changes: 24 additions & 427 deletions MozziConfigExample.h

Large diffs are not rendered by default.

167 changes: 37 additions & 130 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ Teensy 4.0 4.1 | A8 | yes
Gemma M0 | A0 | yes
Adafruit Playground Express | Built in Speaker | yes
Sanguino | 13 | -
STM32F1 maple core (see "Hardware specific notes", below) | PB8 | yes
STM32F1 STM core (see "Hardware specific notes", below) | PA8 | yes
STM32F4 STM core (see "Hardware specific notes", below) | PA8 | yes
STM32F1 maple core | PB8 | yes
STM32F1 STM core | PA8 | yes
STM32F4 STM core | PA8 | yes
ESP8266 *see details* | GPIO2 | yes
RP2040 | 0 | yes

Expand All @@ -99,8 +99,9 @@ void updateControl(){
// your control code
}
int updateAudio(){
// your audio code which returns an int between -244 and 243
AudioOutput_t updateAudio() {
// your audio code which returns a 0-centered integer, typically in the 8bit or 16-bit range
return MonoOutput::from16Bit( [myvalue] );
}
void loop() {
Expand All @@ -122,21 +123,20 @@ Look for code and usage changes [here](extras/NEWS.txt).

***

## Caveats and Workarounds

#### AVR
## General caveats and Workarounds

* While Mozzi is running, calling `delay()`, `delayMicroseconds()`, or other functions which wait or cycle through loops can cause audio glitches.
Mozzi provides `EventDelay()` for scheduling instead of `delay`.

* `analogRead()` is replaced by `mozziAnalogRead()`, which works in the background instead of blocking the processor.
Mozzi provides `EventDelay()` for scheduling instead of `delay`. In general, make sure to write non-blocking code!

* Mozzi interferes with `analogWrite()`. In `STANDARD` and `STANDARD_PLUS` audio modes, Mozzi takes over Timer1 (pins 9 and 10), but you can use the Timer2 pins, 3 and 11 (your board may differ). In `HIFI` mode, Mozzi uses Timer1 (or Timer4 on some boards), and Timer2, so pins 3 and 11 are also out.
If you need `analogWrite()`, you can do PWM output on any digital pins using the technique in *Mozzi>examples>11.Communication>Sinewave_PWM_pins_HIFI*.
* `analogRead()` is a time-consuming operation especially on the classic AVR boards. Mozzi provides `mozziAnalogRead()` as a drop-in replacement, which works in the
background instead of blocking the processor.

* Depending on the hardware and configured audio output mode, Mozzi will usually claim one or more hardware timers. This may affect, among other things, the ability to
use `analogWrite()`. Check the [Hardware Section of the Documentation](https://sensorium.github.io/Mozzi/doc/html/group__hardware.html) to options to configure ressource
usage.
- If you need `analogWrite()`, you can do PWM output on any digital pins using the technique in *Mozzi>examples>11.Communication>Sinewave_PWM_pins_HIFI*.

#### Last Resort
The timers can be made available with `stopMozzi()`, which stops audio interrupts, until you call `startMozzi()`.
* As last resort, the timers can be made available with `stopMozzi()`, which stops audio interrupts, until you call `startMozzi()`.

***

Expand All @@ -150,6 +150,9 @@ It’s explained more thoroughly (for Windows) [here](http://www.instructables.c

If you still need more speed, Arduino 1.0.5 produces slightly faster code.

Mozzi itself offers many helpers for producing faster code, such as Fixed-Point integer maths, fast replacements for `map()`, `random()`, `millis()`, and other functions.
Be sure to use these!

***

## Using external chips to produce the sound
Expand Down Expand Up @@ -188,121 +191,25 @@ Various examples from [Pure Data](http://puredata.info/) by Miller Puckette
[Practical synthesis tutorials](http://www.obiwannabe.co.uk/) by Andy Farnell


## Hardware specific notes

TODO link to hardware section in API docs
TODO list just the basic headers, here.

### Teensy 3.0/3.1/3.2/3.4/3.5/LC


### Teensy 4.0/4.1

### STM32

### SAMD21 architecture (Arduino Circuitplayground M0 and others)
port by Adrian Freed

- Currently, only output on the inbuilt DAC (pin DAC0) is supported. So, obviously, boards without a DAC are not yet convered (in theory you can still use EXTERNAL_AUDIO_OUTPUT)
- Output resolution is fixed at 10 bits. If your board supports more, configure in AudioConfigSAMD21.h
- mozziAnalogRead() and AUDIO_INPUT are not implemented (contributions welcome)
- We don't have a lot of data, which boards this port has been tested on. Success or not, let us know, if you are using Mozzi on SAMD21 boards

### ESP8266
port by Thomas Friedrichsmeier

- Since flash memory is not built into the ESP8266, but connected, externally, it is much too slow for keeping wave tables, audio samples, etc. Instead, these are kept in RAM on this platform.
- Asynchronous analog reads are not implemented. `mozziAnalogRead()` relays to `analogRead()`.
- AUDIO_INPUT is not implemented.
- twi_nonblock is not ported
- Several audio output modes exist, the default being PDM_VIA_SERIAL (configurable in AudioConfigESP.h):
- PDM_VIA_SERIAL: Output is coded using pulse density modulation, and sent via GPIO2 (Serial1 TX).
- This output mode uses timer1 for queuing audio sample, so that timer is not available for other uses.
- Note that this mode has slightly lower effective analog output range than PDM_VIA_I2S, due to start/stop bits being added to the output stream.
- PDM_VIA_I2S: Output is coded using pulse density modulation, and sent via the I2S pins. The I2S data out pin (GPIO3, which is also "RX") will have the output,
but *all* I2S output pins (RX, GPIO2 and GPIO15) will be affected. Mozzi tries to set GPIO2 and GPIO15 to input mode, and *at the time of this writing*, this allows
I2S output on RX even on boards such as the ESP01 (where GPIO15 is tied to Gnd). However, it seems safest to assume that this mode may not be useable on boards where
GPIO2 or GPIO15 are not available as output pins.
- EXTERNAL_DAC_VIA_I2S: Output is sent to an external DAC (such as a PT8211), digitally coded. This is the only mode that supports STEREO. It also needs the least processing power.
- There is no "HIFI_MODE" in addition to the above output options. For high quality output, either use an external DAC, or increase the PDM_RESOLUTION value.
- Note that the ESP8266 pins can output less current than the other supported CPUs. The maximum is 12mA, with a recommendation to stay below 6mA.
- WHEN CONNECTING A HEADPHONE, DIRECTLY, USE APPROPRIATE CURRENT LIMITING RESISTORS (>= 500Ohms).
- _Any_ WiFi-activity can cause severe spikes in power consumption. This can cause audible "ticking" artifacts, long before any other symptoms.
- If you do not require WiFi in your sketch, you should turn it off, _explicitly_, using `WiFi.mode(WIFI_OFF)`.
- A juicy enough, well regulated power supply, and a stabilizing capacitor between VCC and Gnd can help a lot.
- As the (PDM) output signal is digital, a single (fast!) transistor can be used to amplify it to an independent voltage level.
- The audio output resolution is always 16 bits on this platform, _internally_. Thus, in updateAudio(), you should scale your output samples to a full 16 bit range. The effective number of output bits cannot easily
be quantified, due to PDM coding.
- audioHook() calls `yield()` once for every audio sample generated. Thus, as long as your audio output buffer does not run empty, you should not need any additional `yield()`s inside `loop()`.

### ESP32
port by Dieter Vandoren and Thomas Friedrichsmeier

- Since flash memory is not built into the ESP32, but connected, externally, it is much too slow for keeping wave tables, audio samples, etc. Instead, these are kept in RAM on this platform.
- Asynchronous analog reads are not implemented. `mozziAnalogRead()` relays to `analogRead()`.
- AUDIO_INPUT is not implemented.
- twi_nonblock is not ported
- Currently, three audio output modes exist, the default being INTERNAL_DAC (configurable in AudioConfigESP32.h). *The configuration details may still be subject to change; please be prepared to make some minimal adjustments to your code, when upgrading Mozzi*:
- INTERNAL_DAC: Output using the built-in DAC on GPIO pins 25 and 26.
- 8 bits resolution, mono (on both pins) or stereo
- For simplicity of code, both pins are always used, even in mono output mode
- PT8211_DAC: Output is sent via I2S in a format suitable for the PT8211 external EXTERNAL_DAC
- 16 bits resolution, mono or stereo. Remember to shift your audio accordingly.
- Output pins can be configured in AudioConfigESP32.h. Default is BCK: 26, WS: 15, DATA: 33
- PDM_VIA_I2S: Output is converted using pulse density modulation, sent to the I2S data pin. No external hardware needed.
- 16 bits resolution. Remember to shift your audio accordingly.
- Output (DATA) pin can be configured in AudioConfigESP32.h. Default 33. Note that the BCK and WS pins are also used in this mode.
- The PDM_RESOLUTION parameter can be used to reduce noise at the cost of more CPU power.
- Mono, only.
- "HIFI_MODE" is not currently implemented, but could conceivably be realized for the INTERNAL_DAC mode. Patches welcome.
- WIFI-activity not yet tested, but likely the same notes as for ESP8266 apply. Consider turning off WIFI.
- The implementation of audioTicks() may be slightly inaccurate on this platform.

### RP2040 (Raspberry Pi Pico)
port by Thomas Friedrichsmeier

Compiles and runs using [this core](https://github.com/earlephilhower/arduino-pico). Can probably be ported to the Mbed core for RP2040, relatively easily, as it relies mostly
on the RP2040 SDK API. Tested on a Pi Pico.

- This is a recent addition, implementation details may still change (currently just PWM driven by a timer; this may be worth changing to a DMA driven output)
- Wavetables and samples are not kept in progmem on this platform. While apparently speed (of the external flash) is not much of an issue, the data always seems to be copied into RAM, anyway.
- Currently, two audio output modes exist (configurable in AudioConfigRP2040.h) in addition to using an user-defined `audioOutput` function, with the default being PWM_VIA_BARE_CHIP:
- PWM_VIA_BARE_CHIP: PWM audio output on pin 0, by default, with 11 bits default output resolution
- One hardware timer interrupt and one DMA channel are claimed (number not hardcoded), a non-exclusive handler is installed on DMA_IRQ_0.
- HIFI_MODE not yet implemented (although that should not be too hard to do).
- EXTERNAL_DAC_VIA_I2S: I2S output to be connected to an external DAC
- 16 bits resolution by default (configurable in AudioConfigRP2040.h), 8, 16, 24 (left aligned) and 32 resolution are available.
- Both plain I2S and LSBJ_FORMAT (for the PT8211 for instance) are available (configurable in AudioConfigRP2040.h), default is LSBJ.
- Outputs pins can be configured in AudioConfigRP2040.h. Default is BCK: 20, WS: 21, DATA: 22.
- Two DMA channels are claimed (numbers not hardcoded), non-exclusive handlers are installed on DMA_IRQ_0.
- At the time of writing, LSBJ is only available with github arduino-pico core.
- Note that AUDIO_INPUT and mozziAnalogRead() return values in the RP2040's full ADC resolution of 0-4095 rather than AVR's 0-1023.
- twi_nonblock is not ported
- Code uses only one CPU core

### Arduino Giga/MBED
port by Thomas Friedrichsmeier & Thomas Combriat

Compiles and runs using Arduino's standard and Arduino_AdvancedAnalog libraries. This port is still **experimental**, testing reveals some instabilities for some configurations (in particular with USE_AUDIO_INPUT) that are under active investigations.

- This port is not complete yet, in particular:
- Asynchroneous analog reads are not implemented (yet), `mozziAnalogRead()` relays to `analogRead()`.
- HIFI mode is not implemented.
- In addition to using an user-defined `audioOutput()` by setting `EXTERNAL_AUDIO_OUTPUT` to `true` in mozzi_config.h, two bare chip output modes exist (configurable in AudioConfigMBED.h):
- INTERNAL_DAC: uses the DAC present on the board and outputs by default on pin A13 (3.5mm jack connector's tip). Stereo mode uses pin A12 (3.5mm jack connector's first ring) additionally.
- PDM_VIA_SERIAL: returns a pulse-density modulated signal on one of the hardware UART of the board (Serial ports). Default is using the SERIAL2, on pin D18.
- This port should support other MBED based Arduino boards like the Arduino Portenta, in *theory*. It has only been tested on the giga but feedbacks are welcome!

### Arduino Uno R4
port by Thomas Combriat

Compiles and runs using Arduino's standard library (Renesas 0.8.7 at the time of this writing).

- A few particularities:

- Because this board has an on-board DAC (A0), but only one, STEREO is not implemented and Mozzi uses this pin. Usage of other pins using PWM for instance is not implemented yet.
- Two timers are claimed by Mozzi when using the on-board DAC, one when using `EXTERNAL_AUDIO_OUTPUT`.
- `mozziAnalogRead()` returns values in the Renesas' full ADC resolution of 0-16384 rather than AVR's 0-1023. *This might change in the near future for speed purposes.*
## Hardware compatibility and hardware specific notes

While originating on the 8 bit AVR based "classic Arduino" boards, Mozzi supports a wide variety of different MCUs, these days, including:
- Classic AVR boards: Arduino Uno, Duemilanove, Nano, Nano 33, Pro Mini, Leonardo, Mega, many others, and countless clones, Teensy 1 and 2.x, ...
- Various Teensy 3.x boards: Teensy 3.0/3.1/3.2/3.4/3.5/LC
- Teensy 4.x boards: Teensy 4.0 and 4.1 are known to work, future boards stand good chances of working with Mozzi out of the box
- STM32-based boards: Confusingly, several popular Arduino cores exist for these MCUs - and Mozzi supports several. Refer to the documentation
linked below. Mozzi has been tested on the popule STM32F1 "blue pill" and STM32F4 "black pill" boards, but should support a very wide range
of further boards out of the box.
- SAMD21-based boards: Tested on the Arduino Circuitplayground M0, expect to work on others, too.
- ESP8266: Should run on the whole range of boards, including the minimal ESP-01
- ESP32: Should run on the wohle range of boards
- Arduiono Giga/MBED: The Arduino Giga, and - in untested theory - the Arduion Portenta
- RP2040: The Raspberry Pi Pico and other boards using RP2040
- Arduino Uno R4: The new Uno, based on a 32-bit Renesas MCU

Since the hardware capatibilies of these boards are vastly different, the ports, too, differ in their internals and their capabilities. Importantly,
of course, they also differ in what pin(s) are used for audio output by default. Refer to the [Hardware Section of the Documentation](https://sensorium.github.io/Mozzi/doc/html/group__hardware.html) for the details
applicable to your hardware.


***
Expand Down
79 changes: 77 additions & 2 deletions internal/config_checks_avr.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,82 @@
/** For Mozzi-internal use: Apply hardware specific config defaults and config checks: AVR */

// Step 1: Apply missing defaults
// NOTE: This step is actually required for all ports
/** @ingroup hardware
* @page hardware_avr Mozzi on classic Arduino, Teensy 2.x, Arduino Mega, and other 8 bit "AVR"/ATMEGA architecture boards
*
* @section avr_status Port status and notes
* This is the original "port" of Mozzi, and thus very elaborate. The main challenges on this platform, compared to other MCUs, are limitations in
* flash, RAM, and CPU power.
*
* @section avr_output Output modes
* The following audio modes (see @ref MOZZI_AUDIO_MODE) are currently supported on this hardware. In all cases, Timer 1 is claimed, and
* is not available for any other purpose:
* - MOZZI_OUTPUT_PWM
* - MOZZI_OUTPUT_2PIN_PWM
* - MOZZI_OUTPUT_EXTERNAL_TIMED
* - MOZZI_OUTPUT_EXTERNAL_CUSTOM
*
* In all cases, except MOZZI_OUTPUT_EXTERNAL_CUSTOM, Timer 1 is claimed, and is not available for any other purpose.
*
* @section avr_pwm MOZZI_OUTPUT_PWM
* For MOZZI_OUTPUT_PWM, output is restricted to pins that are hardware-attached to Timer 1, but can be configured
* within this tight limit. In particular, the default setup on the
* Arduino UNO is:
* - Mono: Pin 9 -> configurable using MOZZI_AUDIO_PIN_1
* - Stereo: Pin 9 (left) and Pin 10 (right) -> configurable using MOZZI_AUDIO_PIN_1 and MOZZI_AUDIO_PIN_2
* For pinouts on other boards, refer to config/known_16bit_timers.
*
* Rate of the PWM output can be controlled separately from MOZZI_AUDIO_RATE: MOZZI_PWM_RATE.
*
* The available sample resolution is 488, i.e. almost 9 bits, providing some headroom above the 8 bit table resolution
* currently used by the oscillators. You can look at the TimerOne library for more info about how interrupt rate and pwm resolution relate.
*
* @section avr_2pin_pwm MOZZI_OUTPUT_2PIN_PWM
* In this mode, output is split across two pins (again, both connected to Timer 1), with each outputting 7 bits for a total of 14. This allows for
* much better dynamic range, providing much more definition than can be achieved using @ref avr_pwm , while using
* only modestly more processing power. Further, it allows for a much higher PWM carrier rate can be much higher (125 kHz by default; see @ref
* MOZZI_PWM_RATE), which is well beyond the audible range.
*
* On the downside, this mode requires an extra hardware timer (Timer2 in addition to Timer1), which may increase compatibility
* problems with other Arduino libraries that also require a timer. Further, a more elaborate hardware setup is needed, making it less convenient
* for rapid prototyping:
*
* TODO: Move this bit to a dedicated page on output circuits?
* In hardware, add the two signals through a 3.9k resistor on the "high" pin and 499k resistor on "low" pin.
* Use 0.5% resistors or select the most accurate from a batch. It is further recommended to place a 4.7nF capacitor between the summing junction
* of the resistors and ground. This is discussed in much more detail on http://www.openmusiclabs.com/learning/digital/pwm-dac/dual-pwm-circuits/
* Also, there are higher quality output circuits are on the site.
*
* On the classic Arduino Uno, the default pinout in this mode is:
* - Pin 9 (high bits) and Pin 10 (low bits) -> configurable using MOZZI_AUDIO_PIN_1 and MOZZI_AUDIO_PIN_1_LOW
*
* Here is table of the default pins on some other boards. Rows with an x on it have actually been tested (and importantly, the outcome recoreded;
* input welcome on further boards.)
*
* resistor.....3.9k......499k \n
* x................9..........10...............Arduino Uno \n
* x................9..........10...............Arduino Duemilanove \n
* x................9..........10...............Arduino Nano \n
* x................9..........10...............Arduino Leonardo \n
* x................9..........10...............Ardweeny \n
* x................9..........10...............Boarduino \n
* x...............11.........12...............Freetronics EtherMega \n
* .................11.........12...............Arduino Mega \n
* .................14.........15...............Teensy \n
* .............B5(14)...B6(15)...........Teensy2 \n
* x...........B5(25)...B6(26)...........Teensy2++ \n
* .................13.........12...............Sanguino \n
*
* For pinouts on other AVR boards, config/known_16bit_timers might contain some hints.
*
* Rate of the PWM output can be controlled separately from @ref MOZZI_AUDIO_RATE, and is much higher (125kHz), by default: @ref MOZZI_PWM_RATE.
*
* The default sample resolution is 7 bits per pin, for a total of 14 bits. This can be configured within hardware limits (@ref MOZZI_PWM_RATE) using
* @ref MOZZI_AUDIO_BITS_PER_CHANNEL, but beware that increasing this will require even more accuracy in our output resistors (see the linked documentation, above).
*
* @section avr_external MOZZI_OUTPUT_EXTERNAL_TIMED and MOZZI_OUTPUT_EXTERNAL_CUSTOM
* See @ref external_audio
*/


#if not defined(MOZZI_AUDIO_MODE)
#define MOZZI_AUDIO_MODE MOZZI_OUTPUT_PWM
Expand Down
Loading

0 comments on commit 5b946e0

Please sign in to comment.