AVR314 app note

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

Hi all, anyone know if there is any reason why the application note AVR314 does not come with accompanying source code? This sounded like a challenging project, and I am interested in any source code if it is publicly available. Thanks.

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

Hey, I can't find AVR314... what about?

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

Hi, it's a DTMF generation app note for the AVR using PWM and lookup tables in SRAM. There are usually links to source files in the Software section, but not in this particular case, and I was wondering why.

http://www.atmel.com/atmel/produ...
http://www.atmel.com/atmel/acrob...

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

Hi all!

The AVR314 does indeed have source code. I'll send a mail to the AVR freaks webmaster and see if he can do something about it. In the meantime, see below :)

Morten, AVR tech. support

;***************************************************************************
;* 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.asm"
;* Title : DTMF Generator
;* Date : 00.06.27
;* Version : 1.1
;* Target MCU : Any AVR with SRAM, 8 I/O pins and PWM
;*
;* DESCRIPTION
;* This Application note describes how to generate DTMF tones using a single
;* 8 bit PWM output.
;*
;***************************************************************************

.include "4414def.inc"

;**************************************************************************
; REGISTERS
;**************************************************************************
.def XL_Tmp = r1 ; low part temporary register
.def XH_Tmp = r2 ; high part temporary register

; Number of Element (Position) in LUT in Extended format
.def XL_LUTbExt = r3 ; number of LUT-Element of frequency a (low byte)
.def XH_LUTbExt = r4 ; number of LUT-Element of frequency a (high byte)
.def XL_LUTaExt = r5 ; number of LUT-Element of frequency b (low byte)
.def XH_LUTaExt = r6 ; number of LUT-Element of frequency b (high byte)

.def OCR_RelValb = r7 ; low frequency reload value to be written to OCR
.def OCR_RelVala = r8 ; High frequency reload value to be written to OCR

.def x_SWa = r9 ; step width in LUT to get high frequency
.def x_SWb = r10 ; step width in LUT to get low frequency

.def count = r18 ; temporary counter register
.def tmp = r16 ; temp register

.def input = r17 ; input from portB

;**************************************************************************
;**************************************************************************
.equ Xtal = 8000000 ; system clock frequency
.equ prescaler = 1 ; timer1 prescaler
.equ N_samples = 128 ; Number of samples in lookup table
.equ Fck = Xtal/prescaler ; timer1 working frequency
.equ delaycyc = 10 ; port B setup delay cycles

;**************************************************************************
; PROGRAM START - EXECUTION STARTS HERE
;**************************************************************************
.cseg
.org $0
rjmp start ; Reset handler
.org OVF1addr
rjmp tim1_ovf ; Timer1 overflow Handle

;**************************************************************************
; Interrupt timer1
;**************************************************************************
tim1_ovf:
push tmp ; Store temporary register
in tmp,SREG
push tmp ; Store status register
push ZL
push ZH ; Store Z-Pointer
push r0 ; Store R0 Register

;high frequency
mov XL_Tmp,XL_LUTaExt
mov XH_Tmp,XH_LUTaExt
add XL_LUTaExt,x_SWa
clr tmp ; (tmp is cleared, but not the carry flag)
adc XH_LUTaExt,tmp ; Refresh pointer for the next sample
rcall getsample ; read from Sin Wave Sample Table
mov OCR_RelVala,r0 ; OCR_RelVala = high frequency value

;low frequency
mov XL_Tmp,XL_LUTbExt
mov XH_Tmp,XH_LUTbExt
add XL_LUTbExt,x_SWb
clr tmp ; (tmp is cleared, but not the carry flag)
adc XH_LUTbExt,tmp ; refresh pointer for the next sample
rcall getsample ; read from Sin Wave Sample Table
mov OCR_RelValb,r0 ; OCR_RelValb = low frequency value

; scale amplitude
ldi tmp,2
add OCR_RelValb,tmp
lsr OCR_RelValb
lsr OCR_RelValb ; divide 4 and round off
sub r0,OCR_RelValb ; 4/4 - 1/4 = 3/4
mov OCR_RelValb,r0 ; now OCR_RelValb has the right amplitude

clr tmp
out OCR1AH,tmp
mov tmp,OCR_RelVala
add tmp,OCR_RelValb
out OCR1AL,tmp ; send the sum of the two amplitudes to PWM

pop r0 ; Restore R0 Register
pop ZH
pop ZL ; Restore Z-Pointer
pop tmp
out SREG,tmp ; Restore SREG
pop tmp ; Restore temporary register;
reti

;*********************************
; RESET Interrupt
;*********************************
start:
sbi DDRD,PD5 ; Set pin PD5 as output
ldi tmp,low(RAMEND)
out SPL,tmp
ldi tmp,high(RAMEND)
out SPH,tmp ; Initialize Stackpointer

;Initialization of the registers
clr XL_LUTaExt
clr XH_LUTaExt
clr XL_LUTbExt
clr XH_LUTbExt ; Set both table ponters to 0x0000

;enable timer1 interrupt
ldi tmp,(1 PINB high nibble
; column -> PINB low nibble
;**************************************************************************

main:
;high frequency (Esteem only high nibble that is row)
;PB_High_Nibble:
ldi tmp,0x0F
out DDRB,tmp ; High nibble Input / Low nibble. Outp.
ldi tmp,0xF0
out PORTB,tmp ; High nibble PullUp / Low nibble Zero Outp.
rcall delay
clr count
in input,PINB

main10:
inc count
lsl input
brcc main20
ldi tmp,4
cp count,tmp
brne main10
clr x_SWb
clr count
rjmp main30

main20:
dec count
ldi ZL,low(frequencyL*2)
ldi ZH,high(frequencyL*2)
add ZL,count
clr tmp
adc ZH,tmp
lpm
mov x_SWb,r0 ; this is low frequency x_SW
clr count

;low frequency
;PB_Low_Nibble:
main30:
ldi tmp,0xF0
out DDRB,tmp ; High nibble. Outp. / Low nibble Input
ldi tmp,0x0F
out PORTB,tmp ; High nibble Zero Outp. / Low nibble PullUp
rcall delay
in input,PINB
swap input

main40:
inc count
lsl input
brcc main50
ldi tmp,4
cp count,tmp
brne main40
clr x_SWa
rjmp main

main50: ; there is a zero bit in count-1 position
dec count
ldi ZL,low(frequencyH*2)
ldi ZH,high(frequencyH*2)
add ZL,count
clr tmp
adc ZH,tmp
lpm
mov x_SWa,r0 ; this is high frequency x_SW
rjmp main

;****************** DELAY ***********************************
;****************************************************************
delay:
ldi tmp,delaycyc
loop:
dec tmp
brne loop
ret

;****************** GET SAMPLE ******************************
;****************************************************************
getsample:
ldi tmp,0x0f
and XH_Tmp,tmp

; ROUND - add four
ldi tmp,4
add XL_Tmp,tmp
clr tmp
adc XH_Tmp,tmp

; shift (divide by eight):
lsr XH_Tmp
ror XL_Tmp
lsr XH_Tmp
ror XL_Tmp
lsr XH_Tmp
ror XL_Tmp

ldi tmp,0x7f
and XL_Tmp,tmp ; module 128 (samples number sine table)

ldi ZL,low(sine_tbl*2)
ldi ZH,high(sine_tbl*2)
add ZL,XL_Tmp
clr tmp
adc ZH,tmp ; Z is a pointer to the correct
; sine_tbl value
lpm
ret

;*************************** SIN TABLE *************************************
; Samples table : one period sampled on 128 samples and
; quantized on 7 bit
;******************************************************************************
sine_tbl:
.db 64,67
.db 70,73
.db 76,79
.db 82,85
.db 88,91
.db 94,96
.db 99,102
.db 104,106
.db 109,111
.db 113,115
.db 117,118
.db 120,121
.db 123,124
.db 125,126
.db 126,127
.db 127,127
.db 127,127
.db 127,127
.db 126,126
.db 125,124
.db 123,121
.db 120,118
.db 117,115
.db 113,111
.db 109,106
.db 104,102
.db 99,96
.db 94,91
.db 88,85
.db 82,79
.db 76,73
.db 70,67
.db 64,60
.db 57,54
.db 51,48
.db 45,42
.db 39,36
.db 33,31
.db 28,25
.db 23,21
.db 18,16
.db 14,12
.db 10,9
.db 7,6
.db 4,3
.db 2,1
.db 1,0
.db 0,0
.db 0,0
.db 0,0
.db 1,1
.db 2,3
.db 4,6
.db 7,9
.db 10,12
.db 14,16
.db 18,21
.db 23,25
.db 28,31
.db 33,36
.db 39,42
.db 45,48
.db 51,54
.db 57,60

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

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

frequencyH:
.db 107,96
.db 87,79

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

frequencyL:
.db 61,56
.db 50,46

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

Here's the C code too! An unusual way of posting, I know, but it looked okay, didn't it? :)

The 8515 is totally backwards compatible with the part used in this code, the obsolete 4414 :)

Morten

//***************************************************************************
//* 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 : Any AVR with SRAM, 8 I/O pins and PWM
//*
//* DESCRIPTION
//* This Application note describes how to generate DTMF tones using a single
//* 8 bit PWM output.
//*
//***************************************************************************

#include
#define __IAR_SYSTEMS_ASM__
#include
#include "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
//**************************************************************************
flash unsigned char auc_SinParam [128] = {
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 (coloun)
//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 X_LUTaExt = 0; // position freq. A in LUT (extended format)
unsigned int X_LUTbExt = 0; // position freq. B in LUT (extended format)
unsigned int X_LUTa; // position freq. A in LUT (actual position)
unsigned int X_LUTb; // position freq. B in LUT (actual position)

//**************************************************************************
// Timer overflow interrupt service routine
//**************************************************************************
void interrupt [TIMER1_OVF1_vect] ISR_T1_Overflow (void)
{
// move Pointer about step width aheaed
X_LUTaExt += x_SWa;
X_LUTbExt += x_SWb;
// normalize Temp-Pointer
X_LUTa = (char)(((X_LUTaExt+4) >> 3)&(0x007F));
X_LUTb = (char)(((X_LUTbExt+4) >> 3)&(0x007F));
// calculate PWM value: high frequency value + 3/4 low frequency value
OCR1A = (auc_SinParam[X_LUTa] + (auc_SinParam[X_LUTb]-(auc_SinParam[X_LUTb]>>2)));
}

//**************************************************************************
// Initialization
//**************************************************************************
void init (void)
{
TIMSK = 0x80; // Int T1 Overflow enabled
TCCR1A = (1 PINB high nibble
// column -> PINB low nibble
//**************************************************************************

void main (void)
{
unsigned char uc_Input;
unsigned char uc_Counter = 0;
init();
for(;;){
// high nibble - rows
DDRB = 0x0F; // high nibble input / low nibble output
PORTB = 0xF0; // high nibble pull up / low nibble low value
uc_Counter = 0;
Delay(); // wait for Port B lines to be set up correctly
uc_Input = PINB; // read Port B
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
DDRB = 0xF0; // high nibble output / low nibble input
PORTB = 0x0F; // high nibble low value / low nibble pull up
uc_Counter = 0;
Delay(); // wait for Port B lines to be set up correctly
uc_Input = PINB;
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

Hi

I took a look at the Atmel web site, and the file is there, but not linked up properly :-)
I found it, (and have placed the link on the AVR314 Appnote here on AVRfreaks!

(actually I noticed it when looking at this page: http://www.atmel.com/atmel/whats... )

Enjoy!

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

Wow!!! Thanks!!! Err, just as a point for consideration, mebbe links to files should be used instead of code postings, for the benefit of people with bandwidth constraints. Better yet, have a dedicated code posting mechanism that you can link to from within messages. Makes for neater, more quickly ?navigable? threads. Mebbe even a searchable code repository!!! OK, I'm getting carried away...:P Thanks again!!!