AVR314 attempt

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I want to make a fake phone that the user can press the buttons and the sound of the corresponding buttons will be heard in the earpiece. If they enter the correct phone number then the microcontroller will trigger an output for some event to happen. I looked around and found AVR314 and it seemed to be close to what I needed but I needed to modify it for the microcontroller I am using, ATMega168A, and I am using Atmel Studio 6. When I try to debug it, the debugger doesn't follow the logical flow so I am not sure what is going on.  I am not sure what type of speaker (or piezo speaker) I should use or how to wire it. It would be nice if I could use the standard phone hand piece but I can add a different speaker if I need to. It doesn't need to be anything fancy or loud because it will be right next to the user's ear. Here is my modified code that should generate the corresponding tone when a button is pressed. Do you see anything wrong with my conversion?

//***************************************************************************
//* A P P L I C A T I O N   N O T E   F O R   T H E   A V R   F A M I L Y
//*
//* Number               : AVR314
//* File Name            : "dtmf.c"
//* Title                : DTMF Generator
//* Date                 : 00.06.27
//* Version              : 1.0
//* Target MCU           : ATMega168A
//*
//* DESCRIPTION
//* This Application note describes how to generate DTMF tones using a single
//* 8 bit PWM output.
//*
//***************************************************************************

#include <avr/io.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#define __IAR_SYSTEMS_ASM__   
#include <compat/ina90.h>


#define  Xtal       8000000          // system clock frequency
#define  prescaler  1                // timer1 prescaler
#define  N_samples  128              // Number of samples in lookup table
#define  Fck        Xtal/prescaler   // Timer1 working frequency
#define  delaycyc   10               // port B setup delay cycles


//************************** SIN TABLE *************************************
// Samples table : one period sampled on 128 samples and
// quantized on 7 bit
//**************************************************************************

//below modified due to lack of flash type

const unsigned char auc_SinParam [128] PROGMEM= {
64,67,
70,73,
76,79,
82,85,
88,91,
94,96,
99,102,
104,106,
109,111,
113,115,
117,118,
120,121,
123,124,
125,126,
126,127,
127,127,
127,127,
127,127,
126,126,
125,124,
123,121,
120,118,
117,115,
113,111,
109,106,
104,102,
99,96,
94,91,
88,85,
82,79,
76,73,
70,67,
64,60,
57,54,
51,48,
45,42,
39,36,
33,31,
28,25,
23,21,
18,16,
14,12,
10,9,
7,6,
4,3,
2,1,
1,0,
0,0,
0,0,
0,0,
1,1,
2,3,
4,6,
7,9,
10,12,
14,16,
18,21,
23,25,
28,31,
33,36,
39,42,
45,48,
51,54,
57,60};

//***************************  x_SW  ***************************************
//Table of x_SW (excess 8): x_SW = ROUND(8*N_samples*f*510/Fck)
//**************************************************************************

//high frequency (column)
//1209hz  ---> x_SW = 79
//1336hz  ---> x_SW = 87
//1477hz  ---> x_SW = 96
//1633hz  ---> x_SW = 107

const unsigned char auc_frequencyH [4] = {
107,96,
87,79};

//low frequency (row)
//697hz  ---> x_SW = 46
//770hz  ---> x_SW = 50
//852hz  ---> x_SW = 56
//941hz  ---> x_SW = 61

const unsigned char auc_frequencyL [4] = {
61,56,
50,46};


//**************************  global variables  ****************************
unsigned char x_SWa = 0x00;               // step width of high frequency
unsigned char x_SWb = 0x00;               // step width of low frequency
unsigned int  i_CurSinValA = 0;           // position freq. A in LUT (extended format)
unsigned int  i_CurSinValB = 0;           // position freq. B in LUT (extended format)
unsigned int  i_TmpSinValA;               // position freq. A in LUT (actual position)
unsigned int  i_TmpSinValB;               // position freq. B in LUT (actual position)

//**************************************************************************
// Timer overflow interrupt service routine
//**************************************************************************
ISR( TIMER1_OVF_vect)
{ 
  // move Pointer about step width ahead
  i_CurSinValA += x_SWa;       
  i_CurSinValB += x_SWb;
  // normalize Temp-Pointer
  i_TmpSinValA  =  (char)(((i_CurSinValA+4) >> 3)&(0x007F)); 
  i_TmpSinValB  =  (char)(((i_CurSinValB+4) >> 3)&(0x007F));
  // calculate PWM value: high frequency value + 3/4 low frequency value
  
  //Below modified because of the lack of flash type
  //I think I did this correctly.
    
  OCR1A = (pgm_read_byte (&(auc_SinParam[i_TmpSinValA])) + (pgm_read_byte (&(auc_SinParam[i_TmpSinValB]))-(pgm_read_byte (&(auc_SinParam[i_TmpSinValB]))>>2)));
}

//**************************************************************************
// Initialization
//**************************************************************************
void init (void)
{
  TIMSK1  = (1<<TOIE1);                     // Int T0 Overflow enabled
  TCCR1A = (1<<COM1A1)+(1<<WGM10);   // non inverting / 8Bit PWM
  TCCR1B = (1<<CS10);                // CLK/1
  DDRB   = (1 << PINB1);               // PB1 (OC1A) as output
  _SEI();                           // Interrupts enabled
}

//**************************************************************************
// Time delay to ensure a correct setting of the pins of Port B 
//**************************************************************************
void Delay (void)
{
  int i;
  for (i = 0; i < delaycyc; i++) _NOP();
}

//**************************************************************************
// MAIN
// Read from portD (eg: using evaluation board switch) which
// tone to generate, extract mixing high frequency
// (column) and low frequency (row), and then
// fix x_SWa and x_SWb
// row    -> PIND high nibble
// column -> PIND low nibble
//**************************************************************************

int main (void)
{
  volatile unsigned char uc_Input; // had to add.. optimized away
  unsigned char uc_Counter = 0;
  init();
  for(;;){ 
    // high nibble - rows
    DDRD  = 0x0F;                     // high nibble input / low nibble output
    PORTD = 0xF0;                     // high nibble pull up / low nibble low value
    uc_Counter = 0;
    Delay();                          // wait for Port D lines to be set up correctly
    uc_Input = PIND;                  // read Port D
    do 
    {
      if(!(uc_Input & 0x80))          // check if MSB is low
      {
                                      // if yes get step width and end loop
        x_SWb = auc_frequencyL[uc_Counter];  
        uc_Counter = 4;
      }
      else
      {
        x_SWb = 0;                    // no frequency modulation needed
      }
      uc_Counter++;
      uc_Input = uc_Input << 1;       // shift Bits one left
    } while ((uc_Counter < 4));
 
    // low nibble - columns
    DDRD  = 0xF0;                     // high nibble output / low nibble input
    PORTD = 0x0F;                     // high nibble low value / low nibble pull up
    uc_Counter = 0;
    Delay();                          // wait for Port D lines to be set up correctly
    uc_Input = PIND;
    uc_Input = uc_Input << 4;     
    do 
    {
      if(!(uc_Input & 0x80))          // check if MSB is low
      {
                                      // if yes get delay and end loop
        x_SWa = auc_frequencyH[uc_Counter];
        uc_Counter = 4;
      }
      else 
      {
        x_SWa = 0;                 
      }
      uc_Counter++;
      uc_Input = uc_Input << 1;
    } while (uc_Counter < 4);
  } 
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You said:

the debugger doesn't follow the logical flow

Huh?  It would help if you explained what you expect to happen, and what does happen.

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would like to learn how to debug this program in order to learn microcontroller programming. The first thing I did was to try and determine if PINB1 (OC1A) was ever updating when I simulated a button press so I attempted to set a breakpoint in the timer interrupt. I set a breakpoint at the OCRIA line and then ran the program. It never hit the breakpoint. I looked at the ISR routine while it was debugging and the breakpoint had an exclamation point stating that this breakpoint will not be hit. I am not sure why. So I guess the first thing is to determine why the ISR is not working correctly?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well,  you should start by telling GCC that you are using interrupts e.g.

#include <avr/interrupt.h>

Then when you build your program,   you don't get any Warnings.

And since the interrupt vector is actually filled and the ISR() is actually linked,   everything works ok.

 

Where did you obtain your source code?

It is always best to start off with distribution code (and keep a copy)

Then you can 'diff' at any time.

 

Most importantly,   we have some idea of what you have been up to.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First, I want to thak you guys for helping me out, I really appreciate it!

 

ki0bk

Huh? It would help if you explained what you expect to happen, and what does happen.

The degugger doesn't go line by line like the program is written, I have read that it has to do with optimization? The problem in trying to debug, is that you have to mark 2 PINS on PORTD as 1 to simulate a button press. Then as I step through the debugger, it will "reset" one of the pins when it hasn't actually stepped through code that would be resetting it....

 

david.prentice

Where did you obtain your source code?

 I got the source code from Atmels website in the documents section for the ATMega168. Which I think is funny because there are typos in the code and it will not work "off the shelf" as written, but because it came from Atmels, site, I figured it was a good starting point.

And this source code did not have the #include <avr/interrupt.h> statement. AS Studio highlighted ISR( TIMER1_OVF_vect) so I thought it was recoognized or declared somewhere. I will add the #include statement when I get home and try it and report back the results.

It is always best to start off with distribution code (and keep a copy)

And that is why I went with the documentation from Atmel...thought it would be the most reliable source.

Then you can 'diff' at any time.
 

 I am not sure what you mean by that. I am pretty sure it is to compare the two codes to determine what is different? But it sounds like there might be a method or program to identify this? If so, can you point me in the right direction?

 

That is why I wanted to get the distribution code working as written before I started adding the other functionality. the distribution code was only modified to get it to work with the MCU and compiler I was using. From my memory here are the changes I made and the reason:

 

Added #include <avr/io.h> .... compiler complained about it not being there

 

Added #include <avr/pgmspace.h>.... the distribution code used a flash data type but the complier didn't recognize it. From my searching, it looked like I needed this to use the program space. I could be wrong here.
 

Changed #include "ina90.h" to #include <compat/ina90.h>.... another compiler complaint

 

Deleted #include <io4414.h>...as this looked like it wasn't got he MCU I was using and should be called directly

 

Changed the array from  flash unsigned char auc_SinParam [128] = ... to const unsigned char auc_SinParam [128] PROGMEM=... This was again due to the use of the flash data type

 

Changed void interrupt [TIMER1_OVF1_vect] ISR_T1_Overflow (void) to ISR( TIMER1_OVF_vect) because from what I remember (could be faulty) this is the "new" way to do ti
 

Changed OCR1A = (auc_SinParam[i_TmpSinValA] + (auc_SinParam[i_TmpSinValB]-(auc_SinParam[i_TmpSinValB]>>2))); to

OCR1A = (pgm_read_byte (&(auc_SinParam[i_TmpSinValA])) + (pgm_read_byte (&(auc_SinParam[i_TmpSinValB]))-(pgm_read_byte (&(auc_SinParam[i_TmpSinValB]))>>2)));

As I think that is the fix for the flash data type...again I could be wrong.

 

Changed TIMSK = 0x80; to TIMSK1  = (1<<TOIE1); In reading the datasheet for the 168 it looked like this was the correct way to set Timer1 to overflow enabled

 

Changed TCCR1A = (1<<COM1A1)+(1<<PWM10); to TCCR1A = (1<<COM1A1)+(1<<WGM10);   Again to convert to the 168 format. (should this really be TCCR1A = (1<<COM1A1)|(1<<WGM10); 

 

Changed DDRD = (1 << PD5);  to DDRB   = (1 << PINB1); The datasheet for the 168 indicated that PINB1 is the OC1A pin

 

Changed DDRB = 0x0F; and PORTB = 0xF0; to DDRD  = 0x0F; and PORTD = 0xF0; I had to move the port to D because of the conflict with PinB1 being used for OC1A I won't mention the other relevant changes in regards to this same issue

 

I hope that information helps. I really want to learn how to debug my programs and this would be a good start...thanks

 

 

 

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh, yes! Stepping through code with the debugger can be confusing. The debugger will seem to randomly skip from line to line. That's the optimizer confusing things for you. It knows what its doing, but so help me, I don't know what it's doing.

 

Take this bit of nonsense code:

 

char c = PINB ;
for (int i = 0; i<1000; i++)
{
    if (c==3) dothis;
    if (c==7) dothat;
    if (c==13) dotheotherthing;
    c += 1;
}

Now, you go to step through this, and, before it reads PINB into C, it's stepping into the loop? What's this all about? 

 

The compiler has cleverly decided to put 3, 7 and 13 into registers so it can just do a register to register compare. It also might be keeping C itself in a register. So, before it starts the loop, it puts a 3 into one of the registers. Since the 3 comes from the line of code where you compare c with 3, the debugger steps to that line. Then it puts 7 in another register, and the debugger jumps to that line. The same with 13. Sometime later, it will jump to c=PINB when it actually reads the port, then it will hit the for loop, then start into the if statements for real.

 

Yes, I still find myself thinking, "What does it think it is doing?"

 

 

277,232,917 -1 The largest known Mersenne Prime

Measure twice, cry, go back to the hardware store

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Time marches on. Some of the Atmel app notes are 10 years old and written for the Swedish IAR AVR c compiler that costs $3000 a seat. To "port" a c program from IAR to GCC or Codevision or Imagecraft AVR c compilers, you need to sort of knowwhat the path to the include files is in each compilers default directory tree. There are some other differences between compilers, like interrupt declaration and handler syntax. Codevision has a unique port pin notation that some folks like. A good project might be a program that inits the uart, a timer tic interrupt, the a/d, and reads the a/d and prints it out using stdio and printf in each of the 4 compilers. Sort of like a Rosetta stone of AVR c programs. I'll contribute the Imagecraft c source if I can get a volunteer for gcc, iar and cv.

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Some of the Atmel app notes are 10 years old

And the rest!!

 

dusteater wrote:

//* Date                 : 00.06.27

I guess that means 27 June 2000 - so it's going on for fifteen years!

 

But I don't supposed that the principles of DTMF have changed much in that time...

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dusteater wrote:
I would like to learn how to debug this program in order to learn microcontroller programming.

I wouldn't say this is a good point to start for learning microcontroller programming!

 

Start with something simpler, and develop your skills from the ground up - learn to crawl before trying to run!

 

https://www.avrfreaks.net/comment...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well,    I have just returned from the pub.    So do not take too much notice.

 

I just added the "main.c" to a AS6.2 project.

I needed to include <avr/interrupt.h> in order to recognise ISR() as an interrupt service routine instead of an uncalled function.

 

Then the Simulation looked normal.

 

If you want your readers to spend their own time sorting out your problems,   it is worth putting in some effort yourself.

 

For example,   if you say that AVR314 does not build "out of the box" with IAR (or GCC)

I would be happy to help.

 

If you just hack an App Note with no explanation,    I am a little reluctant.

 

In other words,   if your problem is genuine,   I will build and debug the distribution AVR314 on real hardware.

 

David.

Last Edited: Wed. Jan 28, 2015 - 11:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And I have a dtmf generator that runs on a mega32 and compiles with the excellent imagecraft compiler. It was on the legacy avrfreaks site, but I'll dust it off if someone wants to see it.

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Torby, Thanks for explaining why the debugger jumps around...the loop issue was exactly what I was seeing, that helps a lot.

 

Awneil, this isn't my first project, I have created several, this is my next step....Thanks for the link!

 

david.prentice. Adding the #include <avr/interrupt.h> helped a lot. And I am willing to put forth time myself, I spend a couple hours trying to figure things out myself before I even post anything. That was how I was able to convert it to the point I did. I don't expect anyone to create the whole program for me...if they did, then I wouldn't learn myself... I am here to learn first and then get answers.... I know some people come here and expect just to get the answer.

The project I am working on is more than just creating the dial tones, but I wanted to get AVR314 working out of the box first then I could move on. I really appreciate you taking the time to look at it.

What I expected from this code was that PINB1 would have no signal until a button is pressed and then when a button is pressed you would get the corresponding signal and then when the button is released, the signal shuts off. So here is what I have discovered so far...First I am fairly new at the electronics stuff so bear with me. After adding the interrupt include, the simulation did appear to work correctly. So then I put an O Scope on PINB1 and when the MCU starts up, it is outputting a square wave with .29 mS @ 0 V and .22 mS @+5V not quite 50% and I think this puts the frequency at 1.96 KHz?

When a button was pressed, the square wave changed, I couldn't get a reading on the OScope....but it looked like the wave was fluctuating which I assume is because of the dual tone multi frequency but I couldn't figure out how to get a clean looking wave. So then I hooked up a speaker to see what came out. When it was first on, I heard a high pitched tone and then when I pressed a button, I got a different high pitched tone. it did sound like a combination of tones. It sounded like I got the same tone from each button pressed. This is closer but not quite. What should I look at next?

 

Bob, I don't have Imagecraft and not sure if I should purchase this compiler and learn the new interface before I understand things a little more. I don't know what the learning curve would be on this compiler.