Skip to content

Add mtm_hardware.DACOut audio output for the MTM Workshop Computer#10895

Open
todbot wants to merge 36 commits intoadafruit:mainfrom
todbot:mtm_computer_dac_audio
Open

Add mtm_hardware.DACOut audio output for the MTM Workshop Computer#10895
todbot wants to merge 36 commits intoadafruit:mainfrom
todbot:mtm_computer_dac_audio

Conversation

@todbot
Copy link

@todbot todbot commented Mar 21, 2026

Adds a new board-level module mtm_hardware with a DACOut class that provides non-blocking audio playback through the slightly strange MCP4822 dual-channel 12-bit SPI DAC on the Music Thing Modular Workshop Computer.

DACOut follows the same API as audiobusio.I2SOut, accepting any AudioSample (WaveFile, RawSample, Mixer, MP3Decoder) and plays it non-blocking via DMA to a PIO state machine.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be reorganized so that it can be use elsewhere besides this board.

I'd put it in shared-bindings under the mcp4822 name unless this is a common SPI DAC protocol. If it is, then use a more generic name with any mcp4822 specific settings.

Then, move this implementation to common-hal for rp2 (since it is PIO based). Could it be SPI based if we had an internal async SPI API? Maybe have it take in the bus to use?

The board will init it and add an entry to board for using it.

These changes would allow any board build to use it and potentially enable it for "dynamic" use when folks plug it into something.

Thanks!

@todbot
Copy link
Author

todbot commented Mar 23, 2026

I don't see it being of much use to others. This is not a good DAC for doing audio on. We already have the mcp48xx library for more traditional uses.

This DAC frustratingly requires per-sample manipulation (bit sets for channel selection & bit shifts for 16-bit->12-bit conversion) that makes it difficult to use for audio on any other port in CircuitPython that doesn't have a PIO-like module to handle that sample manipulation (since I believe the CircuitPython audio DMA system requires a single address to write to) So, I had to use up most of the PIO program memory to accomplish this.

I'd rather it stay in this board for now and if anyone else asks for it, we can revisit the move to common-hal or shared-bindings.

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you insist, then ok. How about still initing it in board_init and adding it to board? That way folks don't need to know about this module at all.

@todbot
Copy link
Author

todbot commented Mar 23, 2026

I'm also currently trying to put it in audiobusio. Seems like the correct place to put it? Or should it be top level? (I'm not clear what you meant in your original comment)

@tannewt
Copy link
Member

tannewt commented Mar 23, 2026

I'm also currently trying to put it in audiobusio. Seems like the correct place to put it? Or should it be top level? (I'm not clear what you meant in your original comment)

Not in audiobusio because we don't want it enabled everywhere audiobusio is. A new module at the top level please.

@todbot
Copy link
Author

todbot commented Mar 23, 2026

Is it possible to pass in arguments in objects defined in board_init()?
E.g. could a Feather user do spi = board.SPI(half_duplex=True)?
I ask because this DAC takes an optional gain parameter during object instantiation (because it changes the PIO program)

@tannewt
Copy link
Member

tannewt commented Mar 23, 2026

Is it possible to pass in arguments in objects defined in board_init()? E.g. could a Feather user do spi = board.SPI(half_duplex=True)? I ask because this DAC takes an optional gain parameter during object instantiation (because it changes the PIO program)

No, it's meant to just work. I'd suggest making gain an attribute on the object.

@todbot
Copy link
Author

todbot commented Mar 23, 2026

Okay, the 'mcp4822' module is in its own namespace. There's now a CIRCUITPY_MCP4822 define to turn it on. And it's only turned on for the mtm_computer board.

However, I was having some weirdness with make translate where it was picking up changes to files I did not touch. Almost like another commit had not run make translate. In my trying to figure it out I ended up deleting and restoring circuitpython.pot.

If that's too much churn for a PR, I can resubmit this as one change. But I still may get the weird translation changes.

@tannewt
Copy link
Member

tannewt commented Mar 24, 2026

To fix the zephyr builds you'll need to run: https://github.com/adafruit/circuitpython/blob/main/ports/zephyr-cp/cptools/update_board_info.py

(We cache what modules are enabled on zephyr and have a check to make sure every module is listed. We should likely relax it.)

@todbot
Copy link
Author

todbot commented Mar 24, 2026

To fix the zephyr builds you'll need to run: https://github.com/adafruit/circuitpython/blob/main/ports/zephyr-cp/cptools/update_board_info.py

Should I be running this before every commit, as an adjunct to pre-commit?

Copy link
Member

@tannewt tannewt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor things. Getting close! Thanks!

@tannewt
Copy link
Member

tannewt commented Mar 24, 2026

To fix the zephyr builds you'll need to run: https://github.com/adafruit/circuitpython/blob/main/ports/zephyr-cp/cptools/update_board_info.py

Should I be running this before every commit, as an adjunct to pre-commit?

Maybe? It only matters when adding a new module but it should be fast to run.

@todbot
Copy link
Author

todbot commented Mar 25, 2026

A zephyr build is still failing but I can't tell how it's failing or see how I can fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants