Close
0%
0%

ModPlay RISC-V

Playing 4ch Tracker Music MOD-Files on a "$0.10" MCU.

timTim
Similar projects worth following

People often seem to associate low-cost microcontrollers with playing beeps and simple melodies. However, even if MCUs are usually manufactured on trailing-edge semiconductor manufacturing nodes, they are not exempt from Moores law. A "$0.10" 32-Bit Microcontroller today packs significantly more processing power and vastly more powerful peripherals than a AVR/PIC from decades ago.

This is a tiny experiment that plays tracker music MOD format on a WCH CH32V002 RISC-V microcontroller. It is able to play any 4 channel MOD file (of which many are available on The Mod Archive), as long as it fits in the available flash memory.

Based on the MODPlay library, the flash memory footprint of the player is only ~4kb and the CPU usage is between 15% and 25%, depending on whether the code resides in Flash or SRAM, leaving ample time for other tasks.

 You can find the project file in the Github Repo.

  • Future Work

    Tima day ago 0 comments

    This was just an experiment, and I will step back from further work for now. But there is still a lot to do to improve this further.

    • Support for other tracker formats (S3M, XM, IT). I found this project, also called MODplay, quite promising, but the memory footprint is significantly larger (~30kb flash)
    • Stream the tracker file from an attached memory, e.g. a serial NOR flash, to allow for even larger files to be used.
    • Introduce data compression to reduce memory footprint of the MOD files as the MODfiles are quite a redundant data format.
    • Using better digital signal processing techniques to improve audio quality (interpolation, filtering, noise shaping). For example one could go for 8bit PWM resolution at 176kHz sample rate to move all the PWM noise far away from the audio band. Delta-sigma modulation with dithering can then be used to recover the loss in resolution, even going beyond the 11 bit we are using now. 

    A first estimate of achievable SNR vs bit depth with more advanced audio processing is shown below. The two lines indicate 12bit and 14bit effective number of bits (ENOB) after noise shaping.

     MODplay (INT driven) -> Noise shaper -> SRAM (Ring buffer) -> DMA -> Timer PWM -> RC Filter -> Audio Out

    Even low end 32bit microcontrollers are in many instances as capable as a homecomputer / PC from the early 90ies. Powerful DMA feature keep the burden of playing samples off the CPU core. A 32 bit single cycle RISC-V CPU core can very well be compared to a 80486 or 68040, with some limitations regarding memory speed (There are waitstates on flash memory access and no cache).

  • Background

    Tima day ago 0 comments

    A "$0.10" 32-Bit Microcontroller today packs significantly more processing power and vastly more powerful peripherals compared to an AVR/PIC from decades ago.

    The CH32V00x sports a very powerful timer that can run pulse width modulation (PWM) at 48MHz clock. By changing the duty cycle of the PWM signal, we can use it as a (crude) digital to analog converter. The comparator value that determines the duty cycle can be updated directly from SRAM using DMA. This allows for audio sample playback using zero CPU load.

     SRAM (Ring buffer) -> DMA -> Timer PWM -> RC Filter -> Audio Out

    In this experiment, I am using a 22.05kHz sample rate. This means that every PWM period is equal to 48MHZ/22050 = ~2172 clock cycles. This allows for 11 bit (2^11 = 2048) sample resolution, leaving some values unused. This is already quite decent for MOD audio playback, as the source samples before mixing are usually only 8 bit anyway. There are also plenty of options to improve audio quality further with clever digital signal processing.

    Since the CPU is now idling, we can use it to render audio signals in real-time and update the ring buffer when it runs out of data. This can be implemented fully interrupt-driven, so that the music player can run in the background without blocking the main application. Here, I used ModPlay, which is a very tiny footprint MOD-Player that directly outputs into an audio buffer. I modified the source a little to generate mono and scale the signal directly to the PWM range.

    The full pipeline looks like this:

     MODplay (INT driven) -> SRAM (Ring buffer) -> DMA -> Timer PWM (PC3) -> RC Filter -> Audio Out

    I integrated a simple SysTick-based profiler to measure the interrupt handler execution time in real-time. Here is an example output while playing a MOD file with the inner loop running in SRAM for zero wait state execution:

     IRQ: avg=936 us, min=824 us, max=1031 us, rate=172 Hz, CPU=16%

    Everything in flash (two waitstates per 32bit access)

     IRQ: avg=1434 us, min=1230 us, max=1549 us, rate=172 Hz, CPU=24%

    This leaves ample processing time for other tasks, so even on this tiny MCU, we could use a MOD player to run music in the background, while using the remaining processing power for a game engine etc.

    I used a two stage RC low-pass filter (1kohm+10nF, 3dB@~15kHz) to smooth the PWM output. You can see the unfiltered PWM on the top and filtered audio signal on the bottom:

    There is still significant high-frequency noise visible in the filtered audio, but it seems the speakers do a good job of low pass filtering it out further. A better option may be to use a higher PWM frequency and implement noise shaping / delta-sigma modulation to recover SNR.

  • Motivation

    Tima day ago 0 comments

    After seeing this article celebrating some simple beeps on the "$0.10" CH32V003, I was wondering whether we should not have moved beyond the beeper-melody stage of PIC microcontrollers? (Of course, I fell prey to HaD incitive language here, but any motivation is good).

    We will be using the CH32V002 here, which is actually the little brother of the CH32V003 with a much smaller die (~1mm²). compared to the twice as large CH32V003, meaning the V002 is actually even cheaper. However, it comes with the advantage of a hardware multiplaction instruction, which is helpful for audio generation. The project here should work on a V003 nevertheless, albeit with more CPU consumption.

    First, lets have a look at the results:

View all 3 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates