NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Buzzer sound is stretched with ATMega328

January 16, 2016
by lnino
lnino's Avatar

Hey guys,

I have been using my own development board for the last years with my ATMega168. But in some Projects I Need more space for the code and therefore I am playing around with ATMega328.

When I use the the same code and Flash it to m168 the buzzer Sound is great and short. But when I burn the same code (with io_328p.h included) to my 328p the Sound is stretched and sounds like slow Motion.

Any ideas what can cause this behaviour?

Here is the code I am using:

#define F_CPU 14745600

#define D5 851
#define E5 758
#define Fsh5 675
#define G5 637
#define A5 568
#define B5 506
#define C6 477
#define D6 425
#define DUR 40

#define Csh6 450
#define Gsh5 601

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include <inttypes.h>
#include <string.h>

#include <util/delay.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/io_328p.h"

#include "../mylibs/matrix_keypad_eval_brd.c"

// Global Variables
volatile uint8_t number;
volatile uint8_t okay_button;
volatile int32_t finish_count;
volatile int32_t level_count = 0;
volatile uint8_t lv1_var = 0;

// Prototypes
void play_tone(uint16_t, uint8_t);
void play_button_ton();
void play_level_succeed_ton();
void play_level_failed_ton();
void play_final_ton();

int main(void) {

    // internal RC oscillator calibration for 8MHz.
    OSCCAL = 176;

    // Output
    DDRC |= (1<<PC3);   // Buzzer

    init_matrix_keypad();

  while(1)
  {

  // ##################################
  // ##### Button Matrix Section ######
  // ##################################

    //COL1 auf Masse ziehen

    SETBIT(COL1_PORT,COL1_BIT);
    SETBIT(COL2_PORT,COL2_BIT);
    SETBIT(COL3_PORT,COL3_BIT);

    CLEARBIT(COL1_PORT,COL1_BIT);

    asm( "nop" );

    //prüfen, ob ROW 1,2,3,4 einen Low-Pegel aufweisen
    if(!(CHECKBIT(ROW1_PIN,ROW1_BIT))) // When Button 1 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=1;       
    }
    if(!(CHECKBIT(ROW2_PIN,ROW2_BIT))) // When Button 4 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=4;       
    }
    if(!(CHECKBIT(ROW3_PIN,ROW3_BIT))) // When Button 7 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=7;
    }
    if(!(CHECKBIT(ROW4_PIN,ROW4_BIT))) // When Button * pressed
    {
        _delay_ms(120);
        number=10;
    }

    //COL2 auf Masse ziehen

    SETBIT(COL1_PORT,COL1_BIT);
    SETBIT(COL2_PORT,COL2_BIT);
    SETBIT(COL3_PORT,COL3_BIT);

    CLEARBIT(COL2_PORT,COL2_BIT);

    asm( "nop" );

    //prüfen, ob PB 2,3,4 oder 5 einen Low-Pegel aufweisen
    if(!(CHECKBIT(ROW1_PIN,ROW1_BIT))) // When Button 2 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=2;       
    }
    if(!(CHECKBIT(ROW2_PIN,ROW2_BIT))) // When Button 5 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=5;   
    }
    if(!(CHECKBIT(ROW3_PIN,ROW3_BIT))) // When Button 8 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=8;       
    }
    if(!(CHECKBIT(ROW4_PIN,ROW4_BIT))) // When Button 0 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=11;  
    }

    //COL3 auf Masse ziehen

    SETBIT(COL1_PORT,COL1_BIT);
    SETBIT(COL2_PORT,COL2_BIT);
    SETBIT(COL3_PORT,COL3_BIT);

    CLEARBIT(COL3_PORT,COL3_BIT);

    asm( "nop" );

    //prüfen, ob PB 2,3,4 oder 5 einen Low-Pegel aufweisen
    if(!(CHECKBIT(ROW1_PIN,ROW1_BIT))) // When Button 3 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=3;   
    }
    if(!(CHECKBIT(ROW2_PIN,ROW2_BIT))) // When Button 6 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=6;
    }
    if(!(CHECKBIT(ROW3_PIN,ROW3_BIT))) // When Button 9 pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=9;           
    }
    if(!(CHECKBIT(ROW4_PIN,ROW4_BIT))) // When Button # pressed
    {
        play_button_ton();
        _delay_ms(120);
        number=12;      
  }
    return 0;
}

void play_tone(uint16_t delay, uint8_t duration) {
  // delay is half-period in microseconds
  // duration is in 10ms increments

  // example: 440Hz --> delay=1136

  // duration = 2*delay * cycles (all in same units)
  // cycles = 10000 * duration / delay / 2
  // cycles = 100 * duration / (delay/50)
  uint16_t tmp = 100 * duration;
  uint16_t delaysm = delay / 50;
  uint16_t cycles = tmp / delaysm;

  while(cycles > 0) {
    PORTC |= (1<<PC3);
    delay_us(delay);
    PORTC &= ~(1<<PC3);
    delay_us(delay);
    cycles--;
  }
}

void play_button_ton()
{
    play_tone(C6, DUR/2);
}

void play_level_failed_ton()
{
    play_tone(Fsh5, 3*DUR);
}

void play_level_succeed_ton()
{
    play_tone(Csh6, DUR/2);
    play_tone(B5, DUR/2);
    play_tone(Csh6, DUR/2);
}

void play_final_ton()
{
    play_tone(B5, DUR/2);
    play_tone(A5, DUR/2);                   
    play_tone(B5, DUR/2);
    play_tone(A5, DUR/2);
    play_tone(E5, DUR/2);
    play_tone(B5, DUR/2);
    play_tone(A5, DUR/2);                   
    play_tone(B5, DUR/2);
    play_tone(A5, DUR/2);
    play_tone(E5, DUR/2);
}

And the make file 328p:

GCCFLAGS=-g -Os -Wall -mmcu=atmega328p
LINKFLAGS=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm
AVRDUDEFLAGS=-c avr109 -p m328p -b 115200 -P COM8
LINKOBJECTS=../libnerdkits/delay.o ../libnerdkits/lcd.o ../libnerdkits/uart.o

all:    lnino_eval_board-upload

lnino_eval_board.hex:   lnino_eval_board.c
    make -C ../libnerdkits
    avr-gcc ${GCCFLAGS} ${LINKFLAGS} -o lnino_eval_board.o lnino_eval_board.c ${LINKOBJECTS}
    avr-objcopy -j .text -O ihex lnino_eval_board.o lnino_eval_board.hex

lnino_eval_board.ass:   lnino_eval_board.hex
    avr-objdump -S -d lnino_eval_board.o > lnino_eval_board.ass

lnino_eval_board-upload:    lnino_eval_board.hex
    avrdude ${AVRDUDEFLAGS} -U flash:w:lnino_eval_board.hex:a

And the make file for 168:

GCCFLAGS=-g -Os -Wall -mmcu=atmega168 
LINKFLAGS=-Wl,-u,vfprintf -lprintf_flt -Wl,-u,vfscanf -lscanf_flt -lm
AVRDUDEFLAGS=-c avr109 -p m168 -b 115200 -P COM8
LINKOBJECTS=../libnerdkits/delay.o ../libnerdkits/lcd.o ../libnerdkits/uart.o

all:    lnino_eval_board-upload

lnino_eval_board.hex:   lnino_eval_board.c
    make -C ../libnerdkits
    avr-gcc ${GCCFLAGS} ${LINKFLAGS} -o lnino_eval_board.o lnino_eval_board.c ${LINKOBJECTS}
    avr-objcopy -j .text -O ihex lnino_eval_board.o lnino_eval_board.hex

lnino_eval_board.ass:   lnino_eval_board.hex
    avr-objdump -S -d lnino_eval_board.o > lnino_eval_board.ass

lnino_eval_board-upload:    lnino_eval_board.hex
    avrdude ${AVRDUDEFLAGS} -U flash:w:lnino_eval_board.hex:a

I am flashing the 168 bootloader like this:

avrdude -c usbasp -p m168 -e
cd\
cd bootloader168
make fuses
make install

I am flashing the 328 bootloader like that:

avrdude -c usbasp -p m328p -e
cd\
cd bootloader328P
make fuses
make install
January 17, 2016
by Rick_S
Rick_S's Avatar

It sounds like your fuse settings are wrong. New microcontrollers come set to use the internal oscillator at 1MHz. Since your sound is using a delay for its loop, that would be effected by the clock. An easy way to check would be to pull the crystal from the circuit, if the program still runs, then it's running off the internal oscillator. If the program doesn't run, I'd check the crystal value and make sure it's right, or check the fuse settings to make sure the clock divide by 8 is off. (It's on by default on new chips)

January 17, 2016
by lnino
lnino's Avatar

Hi Rick,

thanks for your reply.

I am using the booloader from the nerdkits download. In the folder "bootloader328p" I can see a file called fuses.txt

The Content of the file is:

atmega8:
    low fuse byte:
        clock-source external xtal: CHKSEL = 0

    -> default: 0xe1
       new:     0b11100000 = 0xe0

    high fuse byte:
        512 words bootloader size: BOOTSZ0 = 1
                                   BOOTSZ1 = 0

        reset vector, jump to bootloader on reset: BOOTRST = 0

        no eeprom erase on chip erase: EESAVE = 0

    -> default: 0b11011001 = 0xd9
       new:     0b11010010 = 0xd2

    lock byte:
        SPM is not allowed to write to the Boot Loader section BLB12 = 1
                                                               BLB11 = 0

    -> default: 0b111111 = 0x3f
       new:     0b101111 = 0x2f

atmega88/168:
    low fuse byte:
        clock-source external xtal: CHKSEL = 0

        disable system clock divide by 8: CKDIV8 = 1

    -> default: 0b01100010 = 0x62
       new:     0b11100000 = 0xe0

    high fuse byte:
        no eeprom erase on chip erase: EESAVE = 0

    -> default: 0b11011111 = 0xdf
       new:     0b11010111 = 0xd7

    extended fuse byte:
        512 words bootloader size: BOOTSZ0 = 1
                                   BOOTSZ1 = 0

        OR:
        1024 words bootloader size: BOOTSZ0 = 0
                                    BOOTSZ1 = 0

        reset vector, jump to bootloader on reset: BOOTRST = 0

    -> default: 0b001 = 0x01
       new:     0b010 = 0x02 OR 0x00

    lock byte:
        SPM is not allowed to write to the Boot Loader section BLB12 = 1
                                                               BLB11 = 0

    -> default: 0b111111 = 0x3f
       new:     0b101111 = 0x2f

atmega32:
    high fuse byte
        - enable jtag unprogram: JTAGEN = 1
        - bootloader size 512 words: BOOTSZ1 = 1
                                     BOOTSZ0 = 0
        - jump to bootloader: BOORST = 0

    ->  default: 0b10011001 = 0x99
        neu:     0b11011100 = 0xdc

    low fuse byte:
        - external crystal clock, fast rising power: CKSEL = 1111

    ->  default: 0b11100001 = 0xe1
        neu:     0b11101111 = 0xef

    lock byte:
        SPM is not allowed to write to the Boot Loader section BLB12 = 1
                                                               BLB11 = 0

    -> default: 0b111111 = 0x3f
       new:     0b101111 = 0x2f

atmega644:
    high fuse byte

        - enable jtag unprogram: JTAGEN = 1
        - bootloader size 1024 words: BOOTSZ1 = 1
                                      BOOTSZ0 = 0
        - jump to bootloader: BOORST = 0

    ->  default: 0b10011001 = 0x99
        neu:     0b11011100 = 0xdc

    low fuse byte:

        - external crystal clock, fast rising power: CKSEL3..0 = 0111
                                                     SUT1..0 = 10
        - (unprogram) CKDIV8 = 1

    ->  default: 0b01100010 = 0x62
        neu:     0b11100111 = 0xe7

    lock byte:
        SPM is not allowed to write to the Boot Loader section BLB12 = 1
                                                               BLB11 = 0

    -> default: 0b111111 = 0x3f
       new:     0b101111 = 0x2f

And the make file in this bootloader Folder looks like that:

AVRDUDEFLAGS=-c usbasp -pm328p

all: fuses install

fuses:
    avrdude ${AVRDUDEFLAGS} -U lock:w:0x2f:m
    avrdude ${AVRDUDEFLAGS} -U efuse:w:0x05:m
    avrdude ${AVRDUDEFLAGS} -U hfuse:w:0xd2:m
    avrdude ${AVRDUDEFLAGS} -U lfuse:w:0xf7:m

install:
    avrdude ${AVRDUDEFLAGS} -U flash:w:foodloader.hex:a

Any ideas? I am really new with this fuses stuff. I never needed them. :-)

January 17, 2016
by lnino
lnino's Avatar

Hi Rick,

at the moment I am using my own dev board, so I can't pull the Crystal. Maybe I can test later on a breadboard.

The fuses seams to be okay. The CKDIV8 is disabled.

I found the Explanation of the fuses from Mike:

(modified for ATmega328P!)

EFUSE = 0x05
0  -
0  -
0  -
0  -
0  -
1  BODLEVEL2  (sets V_BOT=2.7)
0  BODLEVEL1    ""
1  BODLEVEL0    ""

HFUSE = 0xd2
1  RSTDISBL
1  DWEN
0  SPIEN
1  WDTON
0  EESAVE
0  BOOTSZ1  (1024 word boot size)
1  BOOTSZ0    ""
0  BOOTRST (jump to bootloader)

LFUSE = 0xf7
1  CKDIV8
1  CKOUT
1  SUT1  (65ms start-up delay)
1  SUT0    ""
0  CKSEL3  (full swing crystal oscillator)
1  CKSEL2    ""
1  CKSEL1    ""
1  CKSEL0    ""

LOCK = 0x2f
0  -
0  -
1  BLB12  (can't self-program over bootloader)
0  BLB11    ""
1  BLB02  (no restrictions on programming application code area)
1  BLB01    ""
1  LB2  (no memory lock)
1  LB1    ""

The are the same as in the make file:

AVRDUDEFLAGS=-c usbasp -pm328p

all: fuses install

fuses:
    avrdude ${AVRDUDEFLAGS} -U lock:w:0x2f:m
    avrdude ${AVRDUDEFLAGS} -U efuse:w:0x05:m
    avrdude ${AVRDUDEFLAGS} -U hfuse:w:0xd2:m
    avrdude ${AVRDUDEFLAGS} -U lfuse:w:0xf7:m

install:
    avrdude ${AVRDUDEFLAGS} -U flash:w:foodloader.hex:a

So I think the fuses might be okay.

Here are the current fuses I am reading out of the MCU with Amtel Studio:

alt image text

Do you have any other ideas at the moment?

The strange Thing is that I am using the same board and code.

January 17, 2016
by Rick_S
Rick_S's Avatar

The fuses do look right, I'm not sure what is causing the problem, but it does seem to be delay related. Try a simple LED blinking program with a set delay that you can time. That would be an easy check. If the LED stays on much longer than expected, then you know something is causing a slowdown. I'm trying to think what could cause a slowdown if the fuses are correct. But at least the simple LED blink test will get us looking in the right direction.

Post a Reply

Please log in to post a reply.

Did you know that a piezoelectric buzzer can be used in reverse as a microphone? Learn more...