⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 goertzel.h

📁 基于AVR制作的电话语音录制系统
💻 H
字号:
#ifndef ___GOERTZEL_H
#define ___GOERTZEL_H

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

#include "gcos.h"         // for the GCOSXXXX constants
#include "commands.h"

#define MAXGOERTZELITEMS          (sizeof(gcos)/sizeof(gcos[0]))
#define GOERTZEL_BLOCK_SIZE       (AUDIO_BLOCK_LENGTH)

prog_int16_t gcos[] = {
    GCOS0440, //  440Hz - Local Dial, remote ringing and busy tone
    GCOS0697, //  697Hz - DTMF keypad row 1 (digits 1, 2, 3 and A)
    GCOS0770, //  770Hz - DTMF keypad row 2 (digits 4, 5, 6 and B)
    GCOS0852, //  852Hz - DTMF keypad row 3 (digits 7, 8, 9 and C)
    GCOS0941, //  941Hz - DTMF keypad row 4 (digits *, 0, # and D)
    GCOS1209, // 1209Hz - DTMF keypad col 1 (digits 1, 4, 7 and *)
    GCOS1336, // 1336Hz - DTMF keypad col 2 (digits 2, 5, 8 and 0)
    GCOS1477, // 1477Hz - DTMF keypad col 3 (digits 3, 6, 9 and #)
    GCOS1633  // 1633Hz - DTMF keypad col 4 (digits A, B, C and D)
              //          (This last one is almost never present in standard
              //          telephone keypads but it is used in other kinds of
              //          singalling; for instance, a Brazilian Called ID
              //          message is typically "A1<caller number with>C",
              //          where caller number is the 2-digit area code 
              //          followed by the 7 or 8 digit phone number itself
};

volatile short q1[2*MAXGOERTZELITEMS],q2[2*MAXGOERTZELITEMS];
volatile unsigned char  gcount;

volatile short *d,*q;
volatile unsigned char nn,cc,at_least_one,accum_flags;
volatile unsigned short accum[MAXGOERTZELITEMS-1];
volatile unsigned short mag;
volatile short coef;

prog_int8_t dtmf_digits[] = "123A456B789C*0#D";
volatile unsigned char dtmf_frames;

volatile unsigned char ring_frames_on,ring_frames_off;

// This macro implements the inner goertzel round:
//
//     short *d;
//     short y=((d[0]*gcos)>>8)-d[1]+c; d[1]=d[0]; d[0]=y; d+=2;
//
// It uses a 16-bit x 16-bit multiplication, yielding a 32 bit result. The
// shift operation is implemented by simply discarding the last 8 bits.
// Since y is a short, the upper 8 bits are also discarded.
//
// I had to code this in assembler because trying to do this with 16-bit
// arithmetic in C killed precision, and making 'gcos' a signed 32-bit forces
// the entire multiplication to be 32-bit * 32-bit -- which GCC generates in
// a subroutine call with *ten* multiplications, dozens of additions and lots
// of overhead cycles in setting up things; this resulted in more than 100
// cycles per sample, which is clearly unnaceptable.
//
// With this routine, the same task is accomplished in only four multiplies
// and 42 cycles.
//
// Notice that it clobbers r0, r1. GCC uses r1 for other purposes, so
// it must be saved beforehand and restored afterwards.

#define goertzel_inner_16(gcos) \
    asm(                                  \
          "ld    r21,Y            \n\t"   \
          "ldd   r22,Y+1          \n\t"   \
          "ldi   r23,lo8(%0)      \n\t"   \
          "ldi   r16,hi8(%0)      \n\t"   \
          "muls  r16,r22          \n\t"   \
          "mov   r19,r0           \n\t"   \
          "mul   r23,r21          \n\t"   \
          "mov   r18,r1           \n\t"   \
          "mulsu r16,r21          \n\t"   \
          "add   r18,r0           \n\t"   \
          "adc   r19,r1           \n\t"   \
          "mulsu r22,r23          \n\t"   \
          "add   r18,r0           \n\t"   \
          "adc   r19,r1           \n\t"   \
                                          \
          "ldd   r24,Y+2          \n\t"   \
          "ldd   r25,Y+3          \n\t"   \
          "sub   r18,r24          \n\t"   \
          "sbc   r19,r25          \n\t"   \
          "mov   r24,r30          \n\t"   \
          "mov   r25,r31          \n\t"   \
          "add   r24,r18          \n\t"   \
          "adc   r25,r19          \n\t"   \
          "ld    r18,Y            \n\t"   \
          "ldd   r19,Y+1          \n\t"   \
                                          \
          "std   Y+2,r18          \n\t"   \
          "std   Y+3,r19          \n\t"   \
          "st    Y,r24            \n\t"   \
          "std   Y+1,r25          \n\t"   \
                                          \
          "subi  r28,252          \n\t"   \
                                          \
          : : "i" ((gcos)) : "r29","r28","r21","r22",    \
                       "r23", "r24", "r25", "r16", "r18", "r19",   \
                       "r0","r1","r2","memory" );

// This macro implements the inner goertzel round:
//
//     short *d;
//     short y=((d[0]*gcos)>>8)-d[1]+c; d[1]=d[0]; d[0]=y; d+=2;
//
// Since some values of gcos are less thatn 256, this version of the routine
// uses a 16-bit x 8-bit multiplication, yielding a 24 bit result. The
// shift operation is implemented by simply discarding the last 8 bits.
// Since y is a short, the upper 8 bits are also discarded. Overall, these
// facts allows us to use only two multiplications and just 36 cycles, six
// less than the previous one.
//
// Notice that it clobbers r0, r1 and r2. GCC uses r1 for other purposes, so
// it must be saved beforehand and restored afterwards.

#define goertzel_inner_08(gcos) \
    asm(                                  \
          "ld    r21,Y            \n\t"   \
          "ldd   r22,Y+1          \n\t"   \
          "ldi   r23,lo8(%0)      \n\t"   \
          "mul   r23,r21          \n\t"   \
          "mov   r18,r1           \n\t"   \
          "eor   r19,r19          \n\t"   \
          "mulsu r22,r23          \n\t"   \
          "add   r18,r0           \n\t"   \
          "adc   r19,r1           \n\t"   \
                                          \
          "ldd   r24,Y+2          \n\t"   \
          "ldd   r25,Y+3          \n\t"   \
          "sub   r18,r24          \n\t"   \
          "sbc   r19,r25          \n\t"   \
          "mov   r24,r30          \n\t"   \
          "mov   r25,r31          \n\t"   \
          "add   r24,r18          \n\t"   \
          "adc   r25,r19          \n\t"   \
          "ld    r18,Y            \n\t"   \
          "ldd   r19,Y+1          \n\t"   \
                                          \
          "std   Y+2,r18          \n\t"   \
          "std   Y+3,r19          \n\t"   \
          "st    Y,r24            \n\t"   \
          "std   Y+1,r25          \n\t"   \
                                          \
          "subi  r28,252          \n\t"   \
                                          \
          : : "i" ((gcos)) : "r29","r28","r21","r22",    \
                       "r23", "r24", "r25", "r16", "r18", "r19",   \
                       "r0","r1","r2","memory" );

// This macro implements the inner goertzel round:
//
//     short *d;
//     short y=((d[0]*gcos)>>8)-d[1]+c; d[1]=d[0]; d[0]=y; d+=2;
//
// However, one of the gcos coefficients is 1, so the multiplication can
// be skipped altogether. This allows this step to be computed in just 27
// cycles.

#define goertzel_inner_00(gcos) \
    asm(                                  \
          "ld    r18,Y            \n\t"   \
          "ldd   r19,Y+1          \n\t"   \
                                          \
          "ldd   r24,Y+2          \n\t"   \
          "ldd   r25,Y+3          \n\t"   \
          "sub   r18,r24          \n\t"   \
          "sbc   r19,r25          \n\t"   \
          "mov   r24,r30          \n\t"   \
          "mov   r25,r31          \n\t"   \
          "add   r24,r18          \n\t"   \
          "adc   r25,r19          \n\t"   \
          "ld    r18,Y            \n\t"   \
          "ldd   r19,Y+1          \n\t"   \
                                          \
          "std   Y+2,r18          \n\t"   \
          "std   Y+3,r19          \n\t"   \
          "st    Y,r24            \n\t"   \
          "std   Y+1,r25          \n\t"   \
                                          \
          "subi  r28,252          \n\t"   \
                                          \
          : : "i" ((gcos)) : "r29","r28","r21","r22",    \
                       "r23", "r24", "r25", "r16", "r18", "r19",   \
                       "r0","r1","r2","memory" );
                       
                       
#endif // __GOERTZEL_H

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -