Welcome, Guest
Username: Password: Remember me

TOPIC: PWM Audio on Raspberry Pi Zero

PWM Audio on Raspberry Pi Zero 5 years 1 month ago #860

  • ES_Team
  • ES_Team's Avatar
  • Administrator
  • Posts: 23
  • Thank you received: 3
  • Karma: 2
PWM is a simple and easy way to generate sound from a microcontroller/microprocessor. If you want to learn more about the basics of
PWM audio (aka Class D) please read "How Class D audio amplifiers work"

Single vs. Dual PWM?
A single PWM audio system uses one output pin to create the analog audio signal. You can use a second PWM signal in order to get a higher resolution audio.
By selecting the resistor summing ratio (R1 and R2) the second PWM signal will be smaller than the first (representing a series of lower order bits).
For instance, with a resistor ratio of 1:256 (28=256), the first PWM will be the high 8 bits, and the second PWM could be the lower 8 bits,
for a total of 16 bit resolution.

Although the PWM distortion and frequency interference is still there, using dual PWM will result in lower noise floor and better/higher working frequencies (with 12 bits single PWM, the microprocessor needs to count up to 4096 (212). By using 2 x 6 bit PWMs, the microprocessor only needs to count to 64 (26) which makes a faster/better signal.

Mixing resistors tolerance: For a 1:64 mixing ratio (2 x 6bits PWMs) the resistors must be 1/64 = 1.5% to get the full bit depth. Using 1% resistor is fine.

Programming PWM Audio:
The BCM2835 Libraries are used because they have intuitive and simple commands to control the PWM interface and you can archieve fast GPIO frequecies in standard C programming.

Configuring Dual PWM for RaspBerry Pi Using BCM2835 Libraries:

1. First of all start the BCM2835 Library to access GPIO.
    if (!bcm2835_init())
    {printf("bcm2835_init failed. Are you running as root??\n");
      return 1;}
2. Define PWM pins, we are using the default pins GPIO18 and 13:
    bcm2835_gpio_fsel(18,BCM2835_GPIO_FSEL_ALT5 ); //PWM0 signal on GPIO18    
    bcm2835_gpio_fsel(13,BCM2835_GPIO_FSEL_ALT0 ); //PWM1 signal on GPIO13  

3. Set the Clock Divider, usually the higher the clock the better, so the PWM signal stays in the high freqs and far from the audio band. The master clock is always 19.2MHz and the smallest divider is 2 so we have a PWM switching frquency of 19.2/2=9.6MHz.
bcm2835_pwm_set_clock(2); // Max clk frequency (19.2MHz/2 = 9.6MHz)

4. For each channel: enable it, and define markspace or balanced mode (I did not experience any change on sound by selecting one or the other)
    bcm2835_pwm_set_mode(0, 1, 1); //channel 0, markspace mode, PWM enabled.
    bcm2835_pwm_set_mode(1, 1, 1); //channel 1, markspace mode, PWM enabled. 

5. Define the PWM range, we are using dual 6bits (number of bits used on each PWM 26=64)
    bcm2835_pwm_set_range(0,64);   //channel 0, 64 is max range (6bits)
    bcm2835_pwm_set_range(1,64);   //channel 1, 64 is max range (6bits)

The following table shows the frequencies achieved using different dual PWMs bit resolution:
  • Single PWM:
    Bit Resolution   		 PWM freq                     	Resistor Tolerance
    8	1x8bits       		9.6MHz/2^8= 37.5KHz        	0.4%
    12	1x12bits     		9.6MHz/2^12= 2.3KHz        	0.02%
    16	1x16bits     		9.6MHz/2^16= 146Hz         	0.001%
  • Dual PWM:
    Bit Resolution      		PWM freq                    	 Resistor Tolerance
    8   	2x4bits        		9.6MHz/2^4= 600KHz         	3.1%
    12     	2x6bits         	9.6MHz/2^6= 150KHz         	1.5%
    16     	2x8bits         	9.6MHz/2^8= 37.5KHz        	0.4%

For a good audio signal, the PWM switching frequency should be around the hundreds of KHz region, taking this into consideration together with the resistor tolerance, and ADC resolution (MCP3202 is 12 bits) there is a sweet spot using a dual 2x6bits PWM (12 bits resolution at 150KHz switching frequency with 1% tolerance mixing resistors).

note: In the BCM2835 website there is plenty of examples using the PWM libraries.
Last Edit: 5 years 4 weeks ago by ES_Team.
The administrator has disabled public write access.
Time to create page: 0.250 seconds
Powered by Kunena Forum
Joomla SEF URLs by Artio