PWM Audio Library

Relatively good quality analog audio out can be generated by using the RP2040 onboard PWM hardware. It can drive an amplifier for speaker output, or be decoupled using a capacitor to drive a headphone-level signal. Mono and stereo signals can be generated.

All samples are sent to the PWMAudio library as signed 16 bits per sample. Due to frequency limitations of the PWM hardware, at higher bit rates these 16-bits will automatically be reduced to the maximum the hardware can handle.

Multiple PWMAudio devices are supported, depending on availability of DMA channels.

The interface for the PWMAudio device is very similar to the I2S device, and most code can be ported simply by instantiating a PWMAudio object in lieu of an I2S object.

PWM Class API

PWMAudio(pin)

Creates a mono PWM output port. Any pin can be used, but no analogWrite calls are allowed to any other pins using that pin’s PWM slice hardware. See the RP2040 datasheet for more details about PWM slices.

PWMAudio(pin, true)

Creates a stereo PWM output port. Only even pins (left signal) can be used, the next odd pin will automatically be assigned to the right channel (i.e. PWMAudio pwm(0, true); will make GP0 as the left channel, GP1 as the right channel). The same restriction as in mono mode applies.

bool setBuffers(size_t buffers, size_t bufferWords)

Set the number of DMA buffers and their size in 32-bit words. Call before PWMAudio::begin().

When running at high sample rates, it is recommended to increase the bufferWords to 32 or higher (i.e. pwm.setBuffers(4, 32); ).

bool setPin(pin_size_t pin)

Adjusts the pin to connect to the PWM audio output. Only legal before PWMAudio::begin().

bool setStereo(bool stereo)

Adjusts the mono/stereo setting of the PWM audio output. Only legal before PWMAudio::begin().

bool setFrequency(long sampleRate)

Sets the sample frequency, but does not start the PWM device (however if the device was already running, it will wontinue to run at the new frequency).

bool begin()/begin(long sampleRate)

Start the PWM Audio device up with the given sample rate, or with the value set using the prior setFrequency call.

void end()

Stops the PWMAudio device.

void flush()

Waits until all the PWM Audio buffers have been output.

size_t write(int16_t sample, bool sync = true)

Writes a single 16-bit sample to the buffer. It is up to the user to keep track of left/right channels when in stereo mode. In mono mode, one sample is written per timestep while in stereo mode two write() calls are required.

This call will block (wait) until space is available to actually write the data if sync is not specified or set to true.

size_t write(const uint8_t *buffer, size_t size)

Transfers number of bytes from an application buffer to the PWM Audio output buffer. Be aware that size is in bytes* and not samples. Size must be a multiple of 4 bytes. Will not block, so check the return value to find out how many bytes were actually written.

int availableForWrite()

Returns the number of samples that can be written without potentially blocking.

void onTransmit(void (*fn)(void))

Sets a callback to be called when a PWM Audio DMA buffer is fully transmitted. Will be in an interrupt context so the specified function must operate quickly and not use blocking calls like delay() or write to the PWM Audio.