Sound Generation by AVR Micro – Tutorial I

Many project requires some kind of Audio output. For example a burglar alarm, an automated school bell or simple electronic games or even a robot! In Old days we used some some dedicated Music and Audio Effect chip to do that. At that time ICs such as UM66 were very popular. Now in the days of microcontrollers, a good design is to use least number of external components to get the job done. So if you still use external audio ICs with a MCU based design then your design is inefficient and costly. The smart idea is to get most of the job done in software. In this article we will learn step by step how to produce different kinds of audio effect by just using an AVR MCU and A speaker. After reading this you would be able to provide simple sound output in many AVR based projects. So lets get started!

I will start this series with a direct runnable example so that you can burn it into an AVR and see how it sounds! In latter parts I will elaborate how this was achieved. Some techniques that were used to achieve audio generation are.

Hardware

The hardware is ATmega32 running at 16MHz. I used the Low Cost AVR Development board to run the demo. Just hook a small (about 1 or 2 watt ) 8ohm speaker between PB3 and GND and you are ready. Those who don’t have the Low Cost AVR Development board may buy it from our online shop or build it at home as described here. The fuse bytes must be programmed as HIGH FUSE=C9 LOW FUSE=FF.

AVR 40PIN Low Cost Development Board Schematic

 

Sound Generation with AVR Microcontroller

Connecting a Speaker

 

Sound Generation with AVR Microcontrolle

PB3

 

GND

 

Whole setup for simple sound generation with AVR MCU.

Software

The software is written in C language and compiled using the avr-gcc. AVR Studio was used as a front end to avr-gcc. More details on compiling project is here.

File Name: pwmsnd.c


/********************************************************************

DESCRIPTION:   A Simple program to genarate some random 

            musical tone.

MCU:        Atmel AVR ATmega32s

CPU SPEED:     16Mhz

LOW FUSE:      0XFF
HIGH FUSE:     0XC9

NOTE:       Connect a 8ohm speaker between GND and PB3.


AUTHOR:        Avinash Gupta
DATE:          Mar 18, 2010

WEB:        www.eXtremeElectronics.co.in


*** THIS PROJECT IS PROVIDED FOR EDUCATION/HOBBY USE ONLY  ***

*** NO PROTION OF THIS WORK CAN BE USED IN COMMERIAL       ***
*** APPLICATION WITHOUT WRITTEN PERMISSION FROM THE AUTHOR ***

EVERYONE IS FREE TO POST/PUBLISH THIS ARTICLE IN
PRINTED OR ELECTRONIC FORM IN FREE/PAID WEBSITES/MAGAZINES/BOOKS
IF PROPER CREDIT TO ORIGINAL AUTHOR IS MENTIONED WITH LINKS TO
ORIGINAL ARTICLE 

COPYRIGHT (C) 2008-2010 EXTREME ELECTRONICS INDIA.

*********************************************************************/


#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#include "sin.h"

/*

Function To Initialize TIMER0 In Fast
PWWM Mode.

*/
void InitPWM()
{
   /*
   TCCR0 - Timer Counter Control Register (TIMER0)
   -----------------------------------------------

   BITS DESCRIPTION
   
   NO:   NAME   DESCRIPTION
   --------------------------
   BIT 7 : FOC0   Force Output Compare [Not used in this example]
   BIT 6 : WGM00  Wave form generartion mode [SET to 1]

   BIT 5 : COM01  Compare Output Mode        [SET to 1]
   BIT 4 : COM00  Compare Output Mode        [SET to 0]
   BIT 3 : WGM01  Wave form generartion mode [SET to 1]
   BIT 2 : CS02   Clock Select               [SET to 0]
   BIT 1 : CS01   Clock Select               [SET to 0]
   BIT 0 : CS00   Clock Select               [SET to 1]

   The above settings are for
   --------------------------
   Timer Clock = CPU Clock (No Prescalling)
   Mode        = Fast PWM
   PWM Output  = Non Inverted

   */


   TCCR0|=(1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<CS00);

   //Set OC0 PIN as output. It is  PB3 on ATmega16 ATmega32

   DDRB|=(1<<PB3);
}

void main()
{
   uint8_t i;

   InitPWM();

   while(1)
   {

      uint8_t delay,n;

      for(delay=1;delay<=50;delay++)
      {
         for(n=0;n<(51-delay);n++)
         {
            for(i=0;i<=254;i++)
            {
               OCR0=pgm_read_byte_near(sine+i);
               _delay_loop_2(delay);

            }
         }
      }
      for(delay=50;delay>=2;delay--)
      {
         for(n=0;n<(51-delay);n++)
         {
            for(i=0;i<=254;i++)
            {
               OCR0=pgm_read_byte_near(sine+i);
               _delay_loop_2(delay);
            }
         }
      }

   }
}


File Name: sin.h


#include <avr/pgmspace.h>

prog_uint8_t sine[256]={
                     127,
                     130,
                     133,
                     136,
                     139,
                     143,
                     146,
                     149,
                     152,
                     155,
                     158,
                     161,
                     164,
                     167,
                     170,
                     173,
                     176,
                     178,
                     181,
                     184,
                     187,
                     189,
                     192,
                     195,
                     197,
                     200,
                     203,
                     205,
                     207,
                     210,
                     212,
                     214,
                     217,
                     219,
                     221,
                     223,
                     225,
                     227,
                     229,
                     231,
                     232,
                     234,
                     236,
                     237,
                     239,
                     240,
                     242,
                     243,
                     244,
                     245,
                     246,
                     248,
                     248,
                     249,
                     250,
                     251,
                     251,
                     252,
                     253,
                     253,
                     253,
                     254,
                     254,
                     254,
                     254,
                     254,
                     254,
                     254,
                     253,
                     253,
                     253,
                     252,
                     252,
                     251,
                     250,
                     250,
                     249,
                     248,
                     247,
                     246,
                     245,
                     243,
                     242,
                     241,
                     239,
                     238,
                     236,
                     235,
                     233,
                     231,
                     229,
                     227,
                     225,
                     224,
                     221,
                     219,
                     217,
                     215,
                     213,
                     210,
                     208,
                     206,
                     203,
                     201,
                     198,
                     195,
                     193,
                     190,
                     187,
                     185,
                     182,
                     179,
                     176,
                     173,
                     170,
                     167,
                     164,
                     161,
                     158,
                     155,
                     152,
                     149,
                     146,
                     143,
                     140,
                     137,
                     134,
                     131,
                     128,
                     125,
                     121,
                     118,
                     115,
                     112,
                     109,
                     106,
                     103,
                     100,
                     97,
                     94,
                     91,
                     88,
                     85,
                     82,
                     79,
                     76,
                     73,
                     71,
                     68,
                     65,
                     62,
                     60,
                     57,
                     55,
                     52,
                     50,
                     47,
                     45,
                     42,
                     40,
                     38,
                     36,
                     34,
                     31,
                     29,
                     27,
                     26,
                     24,
                     22,
                     20,
                     19,
                     17,
                     15,
                     14,
                     13,
                     11,
                     10,
                     9,
                     8,
                     7,
                     6,
                     5,
                     4,
                     3,
                     3,
                     2,
                     2,
                     1,
                     1,
                     0,
                     0,
                     0,
                     0,
                     0,
                     0,
                     0,
                     1,
                     1,
                     1,
                     2,
                     2,
                     3,
                     4,
                     4,
                     5,
                     6,
                     7,
                     8,
                     9,
                     10,
                     12,
                     13,
                     14,
                     16,
                     17,
                     19,
                     21,
                     22,
                     24,
                     26,
                     28,
                     30,
                     32,
                     34,
                     36,
                     39,
                     41,
                     43,
                     45,
                     48,
                     50,
                     53,
                     55,
                     58,
                     61,
                     63,
                     66,
                     69,
                     72,
                     74,
                     77,
                     80,
                     83,
                     86,
                     89,
                     92,
                     95,
                     98,
                     101,
                     104,
                     107,
                     110,
                     113,
                     116,
                     119,
                     122,
};

HEX File for Simple Sound Generation with AVR.

AVR Studio Project for Simple Sound Generation with AVR.

Request to Readers

Tweak the sound generation algorithm, timing, loops etc to create your own masterpiece. And don’t forget to upload it to Youtube and mail me the link I will post it here !

Video

A live demo ! So lets see how it sounds !

Watch on YouTube.com.

Facing problem with your embedded, electronics or robotics project? We are here to help!
Post a help request.

Avinash

Avinash Gupta is solely focused on free and high quality tutorial to make learning embedded system fun !

More Posts - Website

Follow Me:
FacebookLinkedInGoogle Plus

13 thoughts on “Sound Generation by AVR Micro – Tutorial I

  • By anwar - Reply

    please explain how you have generated the sound wave
    and about sinwave generation
    with best wishes

  • By Ganesh - Reply

    This is very good and usefull project work which reduce the hard ckt used for alarm.
    thanks
    Can we produce some speech sound using PWM?

  • By mystic_sage_1791 - Reply

    Could you explain what “pgm_read_byte_near(sine+i)” does in the above code?

  • By avr-code - Reply

    can i know the funda of the code pls??
    or suggest material that is sufficient to learn this completely!!
    thanks~~

  • By radioactive - Reply

    To produce speech, you would require quite huge memory. Just check out this link, it explains clearly.

    http://avrpcm.blogspot.com/2010/11/playing-8-bit-pcm-using-any-avr.html

  • By poeyice - Reply

    GREAT!! it works on my ATMega 8535 with winavr.. thx dude..

  • By Mark - Reply

    Hello,
    I have a team project assignment in which the first part of the project is to produce 8 different sine waves. I’m having to use the ATmega88, will it be possible with that ?
    The next part of it would be to record the sound using a microphone and then displaying that on a LCD. All of this must be achieved by a single microcontroller so will the ATmega88 suffice ?

    Thanks

  • By Grant - Reply

    Do not drive a speaker directly from the microcontroller like this. If the impedance of the speaker is 8/16ohms, it will consume too much current from the AVR port, and may permanently damage it.

  • Pingback: Problem in Generating Audio from AVR ATmega 32 micro-controller using PWM.

  • By Shekhar - Reply

    I liked the project, but my requirement is little different. I want to play live sound by receiving samples through UART. Can you give me some suggestions on how to implement this. I am creating two buffers and being able to get the data from UART but the sound play quality is completely different, there is lot of hisses in the audio file.

  • By Mandar Joshi - Reply

    I am also using PWM for audio generation on STK600 where my file is sampled at 3906.25Hz and playback code is also for same PWM frequency. I receive audio properly but I get noise in background too. It remains there as long as file is playing. The speaker is connected directly between PWM output pin and ground. Do I need to connect any filtering circuit?? And fuse register values are Low 0xE2, High 0x99 and Extended 0xFF do I need to change those values??

  • By Franz - Reply

    Instead of mapping out each individual value, I usually use half of the parametric equation for a circle to generate my sine waves:

    /*
    The following generates successive values of a sine wave between 0 and 255, via
    x = radius * cos(radians) + offsetX
    or
    y = radius * sin(radians) + offsetY

    Either equation will generate a sine-type wave within the proscribed values, the difference being only in phase.
    */

    int i=0;
    int value;
    double radius = 255; // The range of the wave
    double offset = 128; // The offset from 0 of the wave.
    while(i++) {
    value = radius * sin( (double) i * M_PI / 180.0 ) + offset;
    doSomethingWithValue(i);
    }

    • By Avinash - Reply

      @Franz, sin cos calculations are very slow on 8 bit MCU. Thats why they are precomputed and stored.

Leave a Reply

Your email address will not be published. Required fields are marked *


2 − = one

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>