various changes for STM32F4 file used during SM1000 prototyping
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 4 Jul 2014 22:34:21 +0000 (22:34 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 4 Jul 2014 22:34:21 +0000 (22:34 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@1736 01035d8c-6547-0410-b346-abe4f91aad63

codec2-dev/stm32/Makefile
codec2-dev/stm32/src/machdep.h [new file with mode: 0644]
codec2-dev/stm32/src/power_ut.c [new file with mode: 0644]
codec2-dev/stm32/src/sine.c [new file with mode: 0644]
codec2-dev/stm32/src/sine.h [new file with mode: 0644]
codec2-dev/stm32/src/stm32f4_pwm.c
codec2-dev/stm32/src/system_stm32f4xx.c
codec2-dev/stm32/src/timer_ut.c [new file with mode: 0644]

index 0288407a7111c4a8028240421a49b630af1930d8..dbda50e020acfc62c540fca22492786dd31817a2 100644 (file)
@@ -168,6 +168,7 @@ adc_rec.elf: $(ADC_REC_SRCS)
        $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS)
 
 PWM_UT_SRCS=\
+gdb_stdio.c \
 src/stm32f4_pwm.c \
 src/system_stm32f4xx.c \
 src/startup_stm32f4xx.s \
diff --git a/codec2-dev/stm32/src/machdep.h b/codec2-dev/stm32/src/machdep.h
new file mode 100644 (file)
index 0000000..ef2e649
--- /dev/null
@@ -0,0 +1,51 @@
+/*---------------------------------------------------------------------------*\
+
+  FILE........: machdep.h
+  AUTHOR......: David Rowe
+  DATE CREATED: May 2 2013
+
+  Machine dependant functions.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2013 David Rowe
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2.1, as
+  published by the Free Software Foundation.  This program is
+  distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __MACHDEP__
+#define __MACHDEP__
+
+#ifdef TIMER
+#define TIMER_VAR(...) unsigned int __VA_ARGS__
+#define TIMER_SAMPLE(timestamp) timestamp = machdep_timer_sample()
+#define TIMER_SAMPLE_AND_LOG(timestamp, prev_timestamp, label) \
+    timestamp = machdep_timer_sample_and_log(prev_timestamp, label)
+#define TIMER_SAMPLE_AND_LOG2(prev_timestamp, label) \
+    machdep_timer_sample_and_log(prev_timestamp, label)
+#else
+#define TIMER_VAR(...)
+#define TIMER_SAMPLE(timestamp)
+#define TIMER_SAMPLE_AND_LOG(timestamp, prev_timestamp, label)
+#define TIMER_SAMPLE_AND_LOG2(prev_timestamp, label)
+#endif
+
+void         machdep_timer_init(void);
+void         machdep_timer_reset(void);
+unsigned int machdep_timer_sample(void);
+unsigned int machdep_timer_sample_and_log(unsigned int start, char s[]);
+void         machdep_timer_print_logged_samples(void);
+
+#endif
diff --git a/codec2-dev/stm32/src/power_ut.c b/codec2-dev/stm32/src/power_ut.c
new file mode 100644 (file)
index 0000000..c094aef
--- /dev/null
@@ -0,0 +1,135 @@
+/*---------------------------------------------------------------------------*\\r
+\r
+  FILE........: power_ut.c\r
+  AUTHOR......: David Rowe\r
+  DATE CREATED: 30 May 2014\r
+\r
+  Runs Codec 2, ADC, and DAC, to fully exercise STM32C so we can a feel for\r
+  run-time power consumption for SmartMic and hence dimension regulators.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/*\r
+  Copyright (C) 2014 David Rowe\r
+\r
+  All rights reserved.\r
+\r
+  This program is free software; you can redistribute it and/or modify\r
+  it under the terms of the GNU Lesser General Public License version 2.1, as\r
+  published by the Free Software Foundation.  This program is\r
+  distributed in the hope that it will be useful, but WITHOUT ANY\r
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public\r
+  License for more details.\r
+\r
+  You should have received a copy of the GNU Lesser General Public License\r
+  along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdint.h>\r
+#include <math.h>\r
+\r
+#include "stm32f4xx_conf.h"\r
+#include "stm32f4xx.h"\r
+#include "stm32f4_adc.h"\r
+#include "stm32f4_dac.h"\r
+#include "gdb_stdio.h"\r
+#include "codec2.h"\r
+#include "dump.h"\r
+#include "sine.h"\r
+#include "machdep.h"\r
+\r
+#ifdef __EMBEDDED__\r
+#define printf gdb_stdio_printf\r
+#define fopen gdb_stdio_fopen\r
+#define fclose gdb_stdio_fclose\r
+#define fread gdb_stdio_fread\r
+#define fwrite gdb_stdio_fwrite\r
+#endif\r
+\r
+#define SPEED_TEST_SAMPLES 24000\r
+\r
+/* modifiaction of test used to measure codec2 execuation speed.  We read/write ADC/DAC\r
+   but dont do anything with the samples, as they are at 16 kHz and codec needs 8 kHz.  Just\r
+   trying to exercise everything to get a feel for power consumption */\r
+\r
+static void c2speedtest(int mode, char inputfile[])\r
+{\r
+    struct CODEC2 *codec2;\r
+    short         *inbuf, *outbuf, *pinbuf, *dummy_buf;\r
+    unsigned char *bits;\r
+    int            nsam, nbit, nframes;\r
+    FILE          *fin;\r
+    int            f, nread;\r
+\r
+    codec2 = codec2_create(mode);\r
+    nsam = codec2_samples_per_frame(codec2);\r
+    nframes = SPEED_TEST_SAMPLES/nsam;\r
+    outbuf = (short*)malloc(nsam*sizeof(short));\r
+    inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short));\r
+    nbit = codec2_bits_per_frame(codec2);\r
+    bits = (unsigned char*)malloc(nbit*sizeof(char));\r
+    dummy_buf = (short*)malloc(2*nsam*sizeof(short));\r
+\r
+    fin = fopen(inputfile, "rb");\r
+    if (fin == NULL) {\r
+        printf("Error opening input file: %s\nTerminating....\n",inputfile);\r
+        exit(1);\r
+    }\r
+\r
+    printf("reading samples ....\n");\r
+    nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin);\r
+    if (nread != SPEED_TEST_SAMPLES) {\r
+        printf("error reading %s, %d samples reqd, %d read\n", \r
+               inputfile, SPEED_TEST_SAMPLES, nread);\r
+    }\r
+    fclose(fin);\r
+    \r
+    pinbuf = inbuf;\r
+    for(f=0; f<nframes; f++) {\r
+        //printf("read ADC\n");\r
+        while(adc_read(dummy_buf, nsam*2) == -1);  /* runs at Fs = 16kHz */\r
+\r
+        //printf("Codec 2 enc\n");\r
+       GPIOD->ODR = (1 << 13);\r
+        codec2_encode(codec2, bits, pinbuf);\r
+        pinbuf += nsam;\r
+       GPIOD->ODR &= ~(1 << 13);\r
+        //printf("Codec 2 dec\n");\r
+       codec2_decode(codec2, outbuf, bits);\r
+        \r
+        //printf("write to DAC\n");\r
+        while(dac_write(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */\r
+        //printf(".");\r
+    }\r
+\r
+    free(inbuf);\r
+    free(outbuf);\r
+    free(bits);\r
+    codec2_destroy(codec2);\r
+}\r
+\r
+void gpio_init() {\r
+    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD \r
+    GPIOD->MODER = (1 << 26);            // set pin 13 to be general \r
+                                         // purpose output\r
+}\r
+\r
+int main(int argc, char *argv[]) {\r
+    SystemInit();\r
+    gpio_init();\r
+    machdep_timer_init ();\r
+    adc_open();\r
+    dac_open();\r
+\r
+    printf("Starting power_ut\n");\r
+\r
+    c2speedtest(CODEC2_MODE_1600, "stm_in.raw");\r
+\r
+    printf("Finished\n");\r
+\r
+    return 0;\r
+}\r
+\r
diff --git a/codec2-dev/stm32/src/sine.c b/codec2-dev/stm32/src/sine.c
new file mode 100644 (file)
index 0000000..254a61e
--- /dev/null
@@ -0,0 +1,648 @@
+/*---------------------------------------------------------------------------*\
+                                                                             
+  FILE........: sine.c
+  AUTHOR......: David Rowe                                           
+  DATE CREATED: 19/8/2010
+                                                                             
+  Sinusoidal analysis and synthesis functions.
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 1990-2010 David Rowe
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2.1, as
+  published by the Free Software Foundation.  This program is
+  distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+                               INCLUDES                                      
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "defines.h"
+#include "sine.h"
+#include "kiss_fft.h"
+
+#define HPF_BETA 0.125
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+                               HEADERS                                     
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+void hs_pitch_refinement(MODEL *model, COMP Sw[], float pmin, float pmax, 
+                        float pstep);
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+                               FUNCTIONS                                     
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: make_analysis_window        
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 11/5/94 
+
+  Init function that generates the time domain analysis window and it's DFT.
+
+\*---------------------------------------------------------------------------*/
+
+void make_analysis_window(kiss_fft_cfg fft_fwd_cfg, float w[], COMP W[])
+{
+  float m;
+  COMP  wshift[FFT_ENC];
+  COMP  temp;
+  int   i,j;
+
+  /* 
+     Generate Hamming window centered on M-sample pitch analysis window
+  
+  0            M/2           M-1
+  |-------------|-------------|
+        |-------|-------|
+            NW samples
+
+     All our analysis/synthsis is centred on the M/2 sample.               
+  */
+
+  m = 0.0;
+  for(i=0; i<M/2-NW/2; i++)
+    w[i] = 0.0;
+  for(i=M/2-NW/2,j=0; i<M/2+NW/2; i++,j++) {
+    w[i] = 0.5 - 0.5*cosf(TWO_PI*j/(NW-1));
+    m += w[i]*w[i];
+  }
+  for(i=M/2+NW/2; i<M; i++)
+    w[i] = 0.0;
+  /* Normalise - makes freq domain amplitude estimation straight
+     forward */
+
+  m = 1.0/sqrtf(m*FFT_ENC);
+  for(i=0; i<M; i++) {
+    w[i] *= m;
+  }
+
+  /* 
+     Generate DFT of analysis window, used for later processing.  Note
+     we modulo FFT_ENC shift the time domain window w[], this makes the
+     imaginary part of the DFT W[] equal to zero as the shifted w[] is
+     even about the n=0 time axis if NW is odd.  Having the imag part
+     of the DFT W[] makes computation easier.
+
+     0                      FFT_ENC-1
+     |-------------------------|
+
+      ----\               /----
+           \             / 
+            \           /          <- shifted version of window w[n]
+             \         /
+              \       /
+               -------
+
+     |---------|     |---------|      
+       NW/2              NW/2
+  */
+
+  for(i=0; i<FFT_ENC; i++) {
+    wshift[i].real = 0.0;
+    wshift[i].imag = 0.0;
+  }
+  for(i=0; i<NW/2; i++)
+    wshift[i].real = w[i+M/2];
+  for(i=FFT_ENC-NW/2,j=M/2-NW/2; i<FFT_ENC; i++,j++)
+   wshift[i].real = w[j];
+
+  kiss_fft(fft_fwd_cfg, (kiss_fft_cpx *)wshift, (kiss_fft_cpx *)W);
+
+  /* 
+      Re-arrange W[] to be symmetrical about FFT_ENC/2.  Makes later 
+      analysis convenient.
+
+   Before:
+
+
+     0                 FFT_ENC-1
+     |----------|---------|
+     __                   _       
+       \                 /          
+        \_______________/      
+
+   After:
+
+     0                 FFT_ENC-1
+     |----------|---------|
+               ___                        
+              /   \                
+     ________/     \_______     
+
+  */
+       
+      
+  for(i=0; i<FFT_ENC/2; i++) {
+    temp.real = W[i].real;
+    temp.imag = W[i].imag;
+    W[i].real = W[i+FFT_ENC/2].real;
+    W[i].imag = W[i+FFT_ENC/2].imag;
+    W[i+FFT_ENC/2].real = temp.real;
+    W[i+FFT_ENC/2].imag = temp.imag;
+  }
+
+}
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: hpf         
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 16 Nov 2010
+
+  High pass filter with a -3dB point of about 160Hz.
+
+    y(n) = -HPF_BETA*y(n-1) + x(n) - x(n-1)
+\*---------------------------------------------------------------------------*/
+
+float hpf(float x, float states[])
+{
+    states[0] += -HPF_BETA*states[0] + x - states[1];
+    states[1] = x;
+
+    return states[0];
+}
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: dft_speech          
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 27/5/94 
+
+  Finds the DFT of the current speech input speech frame.
+
+\*---------------------------------------------------------------------------*/
+
+void dft_speech(kiss_fft_cfg fft_fwd_cfg, COMP Sw[], float Sn[], float w[])
+{
+  int  i;
+  COMP sw[FFT_ENC];
+
+  for(i=0; i<FFT_ENC; i++) {
+    sw[i].real = 0.0;
+    sw[i].imag = 0.0;
+  }
+
+  /* Centre analysis window on time axis, we need to arrange input
+     to FFT this way to make FFT phases correct */
+  
+  /* move 2nd half to start of FFT input vector */
+
+  for(i=0; i<NW/2; i++)
+    sw[i].real = Sn[i+M/2]*w[i+M/2];
+
+  /* move 1st half to end of FFT input vector */
+
+  for(i=0; i<NW/2; i++)
+    sw[FFT_ENC-NW/2+i].real = Sn[i+M/2-NW/2]*w[i+M/2-NW/2];
+
+  kiss_fft(fft_fwd_cfg, (kiss_fft_cpx *)sw, (kiss_fft_cpx *)Sw);
+}
+
+/*---------------------------------------------------------------------------*\
+                                                                     
+  FUNCTION....: two_stage_pitch_refinement                     
+  AUTHOR......: David Rowe
+  DATE CREATED: 27/5/94                                
+
+  Refines the current pitch estimate using the harmonic sum pitch
+  estimation technique.
+
+\*---------------------------------------------------------------------------*/
+
+void two_stage_pitch_refinement(MODEL *model, COMP Sw[])
+{
+  float pmin,pmax,pstep;       /* pitch refinment minimum, maximum and step */ 
+
+  /* Coarse refinement */
+
+  pmax = TWO_PI/model->Wo + 5;
+  pmin = TWO_PI/model->Wo - 5;
+  pstep = 1.0;
+  hs_pitch_refinement(model,Sw,pmin,pmax,pstep);
+  
+  /* Fine refinement */
+  
+  pmax = TWO_PI/model->Wo + 1;
+  pmin = TWO_PI/model->Wo - 1;
+  pstep = 0.25;
+  hs_pitch_refinement(model,Sw,pmin,pmax,pstep);
+  
+  /* Limit range */
+  
+  if (model->Wo < TWO_PI/P_MAX)
+    model->Wo = TWO_PI/P_MAX;
+  if (model->Wo > TWO_PI/P_MIN)
+    model->Wo = TWO_PI/P_MIN;
+
+  model->L = floor(PI/model->Wo);
+}
+
+/*---------------------------------------------------------------------------*\
+                                                                
+ FUNCTION....: hs_pitch_refinement                             
+ AUTHOR......: David Rowe                      
+ DATE CREATED: 27/5/94                                                      
+                                                                         
+ Harmonic sum pitch refinement function.                          
+                                                                           
+ pmin   pitch search range minimum         
+ pmax  pitch search range maximum          
+ step   pitch search step size             
+ model current pitch estimate in model.Wo  
+                                                                           
+ model         refined pitch estimate in model.Wo  
+                                                                            
+\*---------------------------------------------------------------------------*/
+
+void hs_pitch_refinement(MODEL *model, COMP Sw[], float pmin, float pmax, float pstep)
+{
+  int m;               /* loop variable */
+  int b;               /* bin for current harmonic centre */
+  float E;             /* energy for current pitch*/
+  float Wo;            /* current "test" fundamental freq. */
+  float Wom;           /* Wo that maximises E */
+  float Em;            /* mamimum energy */
+  float r, one_on_r;   /* number of rads/bin */
+  float p;             /* current pitch */
+  
+  /* Initialisation */
+  
+  model->L = PI/model->Wo;     /* use initial pitch est. for L */
+  Wom = model->Wo;
+  Em = 0.0;
+  r = TWO_PI/FFT_ENC;
+  one_on_r = 1.0/r;
+
+  /* Determine harmonic sum for a range of Wo values */
+
+  for(p=pmin; p<=pmax; p+=pstep) {
+    E = 0.0;
+    Wo = TWO_PI/p;
+
+    /* Sum harmonic magnitudes */
+    for(m=1; m<=model->L; m++) {
+        b = (int)(m*Wo*one_on_r + 0.5);
+        E += Sw[b].real*Sw[b].real + Sw[b].imag*Sw[b].imag;
+    }  
+    /* Compare to see if this is a maximum */
+    
+    if (E > Em) {
+      Em = E;
+      Wom = Wo;
+    }
+  }
+
+  model->Wo = Wom;
+}
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+  FUNCTION....: estimate_amplitudes                          
+  AUTHOR......: David Rowe             
+  DATE CREATED: 27/5/94                               
+                                                                             
+  Estimates the complex amplitudes of the harmonics.    
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+void estimate_amplitudes(MODEL *model, COMP Sw[], COMP W[], int est_phase)
+{
+  int   i,m;           /* loop variables */
+  int   am,bm;         /* bounds of current harmonic */
+  int   b;             /* DFT bin of centre of current harmonic */
+  float den;           /* denominator of amplitude expression */
+  float r, one_on_r;   /* number of rads/bin */
+  int   offset;
+  COMP  Am;
+
+  r = TWO_PI/FFT_ENC;
+  one_on_r = 1.0/r;
+
+  for(m=1; m<=model->L; m++) {
+    den = 0.0;
+    am = (int)((m - 0.5)*model->Wo*one_on_r + 0.5);
+    bm = (int)((m + 0.5)*model->Wo*one_on_r + 0.5);
+    b = (int)(m*model->Wo/r + 0.5);
+
+    /* Estimate ampltude of harmonic */
+
+    den = 0.0;
+    Am.real = Am.imag = 0.0;
+    offset = FFT_ENC/2 - (int)(m*model->Wo*one_on_r + 0.5);
+    for(i=am; i<bm; i++) {
+      den += Sw[i].real*Sw[i].real + Sw[i].imag*Sw[i].imag;
+      Am.real += Sw[i].real*W[i + offset].real;
+      Am.imag += Sw[i].imag*W[i + offset].real;
+    }
+
+    model->A[m] = sqrtf(den);
+
+    if (est_phase) {
+
+        /* Estimate phase of harmonic, this is expensive in CPU for
+           embedded devicesso we make it an option */
+
+        model->phi[m] = atan2(Sw[b].imag,Sw[b].real);
+    }
+  }
+}
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+  est_voicing_mbe()          
+                                                                             
+  Returns the error of the MBE cost function for a fiven F0.
+
+  Note: I think a lot of the operations below can be simplified as
+  W[].imag = 0 and has been normalised such that den always equals 1.
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+float est_voicing_mbe(
+    MODEL *model,
+    COMP   Sw[],
+    COMP   W[],
+    COMP   Sw_[],         /* DFT of all voiced synthesised signal  */
+                          /* useful for debugging/dump file        */
+    COMP   Ew[],          /* DFT of error                          */
+    float prev_Wo)
+{
+    int   i,l,al,bl,m;    /* loop variables */
+    COMP  Am;             /* amplitude sample for this band */
+    int   offset;         /* centers Hw[] about current harmonic */
+    float den;            /* denominator of Am expression */
+    float error;          /* accumulated error between original and synthesised */
+    float Wo;            
+    float sig, snr;
+    float elow, ehigh, eratio;
+    float sixty;
+
+    sig = 1E-4;
+    for(l=1; l<=model->L/4; l++) {
+       sig += model->A[l]*model->A[l];
+    }
+    for(i=0; i<FFT_ENC; i++) {
+       Sw_[i].real = 0.0;
+       Sw_[i].imag = 0.0;
+       Ew[i].real = 0.0;
+       Ew[i].imag = 0.0;
+    }
+
+    Wo = model->Wo;
+    error = 1E-4;
+
+    /* Just test across the harmonics in the first 1000 Hz (L/4) */
+
+    for(l=1; l<=model->L/4; l++) {
+       Am.real = 0.0;
+       Am.imag = 0.0;
+       den = 0.0;
+       al = ceil((l - 0.5)*Wo*FFT_ENC/TWO_PI);
+       bl = ceil((l + 0.5)*Wo*FFT_ENC/TWO_PI);
+
+       /* Estimate amplitude of harmonic assuming harmonic is totally voiced */
+
+        offset = FFT_ENC/2 - l*Wo*FFT_ENC/TWO_PI + 0.5;
+       for(m=al; m<bl; m++) {
+           Am.real += Sw[m].real*W[offset+m].real;
+           Am.imag += Sw[m].imag*W[offset+m].real;
+           den += W[offset+m].real*W[offset+m].real;
+        }
+
+        Am.real = Am.real/den;
+        Am.imag = Am.imag/den;
+
+        /* Determine error between estimated harmonic and original */
+
+        offset = FFT_ENC/2 - l*Wo*FFT_ENC/TWO_PI + 0.5;
+        for(m=al; m<bl; m++) {
+           Sw_[m].real = Am.real*W[offset+m].real;
+           Sw_[m].imag = Am.imag*W[offset+m].real;
+           Ew[m].real = Sw[m].real - Sw_[m].real;
+           Ew[m].imag = Sw[m].imag - Sw_[m].imag;
+           error += Ew[m].real*Ew[m].real;
+           error += Ew[m].imag*Ew[m].imag;
+       }
+    }
+    
+    snr = 10.0*log10f(sig/error);
+    if (snr > V_THRESH)
+       model->voiced = 1;
+    else
+       model->voiced = 0;
+    /* post processing, helps clean up some voicing errors ------------------*/
+
+    /* 
+       Determine the ratio of low freqency to high frequency energy,
+       voiced speech tends to be dominated by low frequency energy,
+       unvoiced by high frequency. This measure can be used to
+       determine if we have made any gross errors.
+    */
+
+    elow = ehigh = 1E-4;
+    for(l=1; l<=model->L/2; l++) {
+       elow += model->A[l]*model->A[l];
+    }
+    for(l=model->L/2; l<=model->L; l++) {
+       ehigh += model->A[l]*model->A[l];
+    }
+    eratio = 10.0*log10f(elow/ehigh);
+
+    /* Look for Type 1 errors, strongly V speech that has been
+       accidentally declared UV */
+
+    if (model->voiced == 0)
+       if (eratio > 10.0)
+           model->voiced = 1;
+
+    /* Look for Type 2 errors, strongly UV speech that has been
+       accidentally declared V */
+
+    if (model->voiced == 1) {
+       if (eratio < -10.0)
+           model->voiced = 0;
+
+       /* A common source of Type 2 errors is the pitch estimator
+          gives a low (50Hz) estimate for UV speech, which gives a
+          good match with noise due to the close harmoonic spacing.
+          These errors are much more common than people with 50Hz3
+          pitch, so we have just a small eratio threshold. */
+
+       sixty = 60.0*TWO_PI/FS;
+       if ((eratio < -4.0) && (model->Wo <= sixty))
+           model->voiced = 0;
+    }
+    //printf(" v: %d snr: %f eratio: %3.2f %f\n",model->voiced,snr,eratio,dF0);
+
+    return snr;
+}
+
+/*---------------------------------------------------------------------------*\
+                                                       
+  FUNCTION....: make_synthesis_window       
+  AUTHOR......: David Rowe                           
+  DATE CREATED: 11/5/94 
+
+  Init function that generates the trapezoidal (Parzen) sythesis window.
+
+\*---------------------------------------------------------------------------*/
+
+void make_synthesis_window(float Pn[])
+{
+  int   i;
+  float win;
+
+  /* Generate Parzen window in time domain */
+
+  win = 0.0;
+  for(i=0; i<N/2-TW; i++)
+    Pn[i] = 0.0;
+  win = 0.0;
+  for(i=N/2-TW; i<N/2+TW; win+=1.0/(2*TW), i++ )
+    Pn[i] = win;
+  for(i=N/2+TW; i<3*N/2-TW; i++)
+    Pn[i] = 1.0;
+  win = 1.0;
+  for(i=3*N/2-TW; i<3*N/2+TW; win-=1.0/(2*TW), i++)
+    Pn[i] = win;
+  for(i=3*N/2+TW; i<2*N; i++)
+    Pn[i] = 0.0;
+}
+
+/*---------------------------------------------------------------------------*\
+                                                                             
+  FUNCTION....: synthesise                           
+  AUTHOR......: David Rowe             
+  DATE CREATED: 20/2/95                       
+                                                                             
+  Synthesise a speech signal in the frequency domain from the
+  sinusodal model parameters.  Uses overlap-add with a trapezoidal
+  window to smoothly interpolate betwen frames.
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+void synthesise(
+  kiss_fft_cfg fft_inv_cfg, 
+  float  Sn_[],                /* time domain synthesised signal              */
+  MODEL *model,                /* ptr to model parameters for this frame      */
+  float  Pn[],         /* time domain Parzen window                   */
+  int    shift          /* flag used to handle transition frames       */
+)
+{
+    int   i,l,j,b;     /* loop variables */
+    COMP  Sw_[FFT_DEC];        /* DFT of synthesised signal */
+    COMP  sw_[FFT_DEC];        /* synthesised signal */
+
+    if (shift) {
+       /* Update memories */
+       for(i=0; i<N-1; i++) {
+           Sn_[i] = Sn_[i+N];
+       }
+       Sn_[N-1] = 0.0;
+    }
+
+    for(i=0; i<FFT_DEC; i++) {
+       Sw_[i].real = 0.0;
+       Sw_[i].imag = 0.0;
+    }
+
+    /*
+      Nov 2010 - found that synthesis using time domain cos() functions
+      gives better results for synthesis frames greater than 10ms.  Inverse
+      FFT synthesis using a 512 pt FFT works well for 10ms window.  I think
+      (but am not sure) that the problem is related to the quantisation of
+      the harmonic frequencies to the FFT bin size, e.g. there is a 
+      8000/512 Hz step between FFT bins.  For some reason this makes
+      the speech from longer frame > 10ms sound poor.  The effect can also
+      be seen when synthesising test signals like single sine waves, some
+      sort of amplitude modulation at the frame rate.
+
+      Another possibility is using a larger FFT size (1024 or 2048).
+    */
+
+#define FFT_SYNTHESIS
+#ifdef FFT_SYNTHESIS
+    /* Now set up frequency domain synthesised speech */
+    for(l=1; l<=model->L; l++) {
+    //for(l=model->L/2; l<=model->L; l++) {
+    //for(l=1; l<=model->L/4; l++) {
+       b = (int)(l*model->Wo*FFT_DEC/TWO_PI + 0.5);
+       if (b > ((FFT_DEC/2)-1)) {
+               b = (FFT_DEC/2)-1;
+       }
+       Sw_[b].real = model->A[l]*cosf(model->phi[l]);
+       Sw_[b].imag = model->A[l]*sinf(model->phi[l]);
+       Sw_[FFT_DEC-b].real = Sw_[b].real;
+       Sw_[FFT_DEC-b].imag = -Sw_[b].imag;
+    }
+
+    /* Perform inverse DFT */
+
+    kiss_fft(fft_inv_cfg, (kiss_fft_cpx *)Sw_, (kiss_fft_cpx *)sw_);
+#else
+    /*
+       Direct time domain synthesis using the cos() function.  Works
+       well at 10ms and 20ms frames rates.  Note synthesis window is
+       still used to handle overlap-add between adjacent frames.  This
+       could be simplified as we don't need to synthesise where Pn[]
+       is zero.
+    */
+    for(l=1; l<=model->L; l++) {
+       for(i=0,j=-N+1; i<N-1; i++,j++) {
+           Sw_[FFT_DEC-N+1+i].real += 2.0*model->A[l]*cos(j*model->Wo*l + model->phi[l]);
+       }
+       for(i=N-1,j=0; i<2*N; i++,j++)
+           Sw_[j].real += 2.0*model->A[l]*cos(j*model->Wo*l + model->phi[l]);
+    }  
+#endif
+
+    /* Overlap add to previous samples */
+
+    for(i=0; i<N-1; i++) {
+       Sn_[i] += sw_[FFT_DEC-N+1+i].real*Pn[i];
+    }
+
+    if (shift)
+       for(i=N-1,j=0; i<2*N; i++,j++)
+           Sn_[i] = sw_[j].real*Pn[i];
+    else
+       for(i=N-1,j=0; i<2*N; i++,j++)
+           Sn_[i] += sw_[j].real*Pn[i];
+}
+
+
+static unsigned long next = 1;
+
+int codec2_rand(void) {
+    next = next * 1103515245 + 12345;
+    return((unsigned)(next/65536) % 32768);
+}
+
diff --git a/codec2-dev/stm32/src/sine.h b/codec2-dev/stm32/src/sine.h
new file mode 100644 (file)
index 0000000..da7dc28
--- /dev/null
@@ -0,0 +1,48 @@
+/*---------------------------------------------------------------------------*\
+                                                                             
+  FILE........: sine.h
+  AUTHOR......: David Rowe                                                          
+  DATE CREATED: 1/11/94
+                                                                             
+  Header file for sinusoidal analysis and synthesis functions.
+                                                                             
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2009 David Rowe
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2.1, as
+  published by the Free Software Foundation.  This program is
+  distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __SINE__
+#define __SINE__
+
+#include "defines.h"
+#include "comp.h"
+#include "kiss_fft.h"
+
+void make_analysis_window(kiss_fft_cfg fft_fwd_cfg, float w[], COMP W[]);
+float hpf(float x, float states[]);
+void dft_speech(kiss_fft_cfg fft_fwd_cfg, COMP Sw[], float Sn[], float w[]);
+void two_stage_pitch_refinement(MODEL *model, COMP Sw[]);
+void estimate_amplitudes(MODEL *model, COMP Sw[], COMP W[], int est_phase);
+float est_voicing_mbe(MODEL *model, COMP Sw[], COMP W[], COMP Sw_[],COMP Ew[], 
+                     float prev_Wo);
+void make_synthesis_window(float Pn[]);
+void synthesise(kiss_fft_cfg fft_inv_cfg, float Sn_[], MODEL *model, float Pn[], int shift);
+
+#define CODEC2_RAND_MAX 32767
+int codec2_rand(void);
+
+#endif
index 340d8beb31ac2a9c1ec762ffe3d43673a3dc7453..776baf5429c02ac40f13f3221b56a7a8b2abe235 100644 (file)
@@ -31,6 +31,7 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include "gdb_stdio.h"
 
 #include "stm32f4xx_gpio.h"
 #include "stm32f4xx_rcc.h"
@@ -155,13 +156,23 @@ void Timer1Config() {
   
     /* Compute the value to be set in ARR regiter to generate signal frequency at FS */
 
+#ifdef TMP
     uhTimerPeriod = (SystemCoreClock / FS ) - 1;
+    gdb_stdio_printf("uhTimerPeriod = %d\n", uhTimerPeriod);
 
     /* Compute CCR1 values to generate a duty cycle at 50% */
 
     for(i=0; i<SINE_SAMPLES; i++) {
         aSRC_Buffer[i] = uhTimerPeriod *((int)aSine[i] + 32768)/(32768*2);
     }
+#else
+    uhTimerPeriod = (SystemCoreClock / 42000000 ) - 1;
+    gdb_stdio_printf("uhTimerPeriod = %d\n", uhTimerPeriod);
+
+    /* Compute CCR1 values to generate a duty cycle at 50% */
+
+    aSRC_Buffer[0] = 2;
+#endif
 
 #ifdef OLD
   /* Compute CCR1 value to generate a duty cycle at 50% */
@@ -208,10 +219,10 @@ void Timer1Config() {
     TIM_Cmd(TIM1, ENABLE);
   
     /* DMA enable*/
-    DMA_Cmd(DMA2_Stream6, ENABLE);
+    //DMA_Cmd(DMA2_Stream6, ENABLE);
   
     /* TIM1 Update DMA Request enable */
-    TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);
+    //TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);
 
     /* Main Output Enable */
     TIM_CtrlPWMOutputs(TIM1, ENABLE);
index 86953137bc6e5fc6184a5e627dce47bd8c2a6005..e1aae444d6b635ed24e0d1687f2363559d897a38 100644 (file)
 \r
 /************************* PLL Parameters *************************************/\r
 /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */\r
-#define PLL_M      8\r
-#define PLL_N      336\r
+#define PLL_M      7\r
+#define PLL_N      342\r
 \r
 /* SYSCLK = PLL_VCO / PLL_P */\r
 #define PLL_P      2\r
diff --git a/codec2-dev/stm32/src/timer_ut.c b/codec2-dev/stm32/src/timer_ut.c
new file mode 100644 (file)
index 0000000..967c87d
--- /dev/null
@@ -0,0 +1,179 @@
+/*---------------------------------------------------------------------------*\
+
+  FILE........: timer_ut.c
+  AUTHOR......: David Rowe
+  DATE CREATED: 3 Jan 2014
+
+  Unit test STM32F4 timer hardware.
+
+\*---------------------------------------------------------------------------*/
+
+/*
+  Copyright (C) 2014 David Rowe
+
+  All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License version 2.1, as
+  published by the Free Software Foundation.  This program is
+  distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stm32f4xx_gpio.h"
+#include "stm32f4xx_rcc.h"
+#include "gdb_stdio.h"
+
+#define TIM1_CCR3_ADDRESS    0x4001223C
+
+TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
+TIM_OCInitTypeDef  TIM_OCInitStructure;
+TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
+uint16_t uhTimerPeriod;
+uint16_t aSRC_Buffer[3] = {0, 0, 0};
+
+void Timer1Config();
+#define FS  3500000
+
+int main(void){
+    Timer1Config();
+ }
+
+/* DR: TIM_Config configures a couple of I/O pins for PWM output from
+   Timer1 Channel 3.  Note I dont think any of this is needed, except
+   perhaps to check timer frequency.  Can be removed down the track. */
+
+/**
+  * @brief  Configure the TIM1 Pins.
+  * @param  None
+  * @retval None
+  */
+static void TIM_Config(void)
+{
+  GPIO_InitTypeDef GPIO_InitStructure;
+  
+  /* GPIOA and GPIOB clock enable */
+  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE);
+
+  /* GPIOA Configuration: Channel 3 as alternate function push-pull */
+  /* Discovery board pin PA10 */
+
+  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ;
+  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
+  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
+  GPIO_Init(GPIOA, &GPIO_InitStructure); 
+  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_TIM1);
+
+  /* GPIOB Configuration: Channel 3N as alternate function push-pull */
+  /* Discovery board pin PB15 */
+
+  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
+  GPIO_Init(GPIOB, &GPIO_InitStructure);
+  GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1);
+}
+
+void Timer1Config() {
+
+    /* TIM Configuration */
+
+    TIM_Config();
+
+    /* TIM1 example -------------------------------------------------
+  
+       TIM1 input clock (TIM1CLK) is set to 2 * APB2 clock (PCLK2), since APB2 
+       prescaler is different from 1.   
+       TIM1CLK = 2 * PCLK2  
+       PCLK2 = HCLK / 2 
+       => TIM1CLK = 2 * (HCLK / 2) = HCLK = SystemCoreClock
+  
+       TIM1CLK = SystemCoreClock, Prescaler = 0, TIM1 counter clock = SystemCoreClock
+       SystemCoreClock is set to 168 MHz for STM32F4xx devices.
+
+       The objective is to configure TIM1 channel 3 to generate complementary PWM
+       signal with a frequency equal to F KHz:
+       - TIM1_Period = (SystemCoreClock / F) - 1
+
+       The number of this repetitive requests is defined by the TIM1 Repetion counter,
+       each 3 Update Requests, the TIM1 Channel 3 Duty Cycle changes to the next new 
+       value defined by the aSRC_Buffer.
+  
+       Note: 
+       SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file.
+       Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate()
+       function to update SystemCoreClock variable value. Otherwise, any configuration
+       based on this variable will be incorrect.  
+       -----------------------------------------------------------------------------*/
+  
+    /* Compute the value to be set in ARR regiter to generate signal frequency at FS Hz */
+    uhTimerPeriod = (SystemCoreClock / FS ) - 1;
+    /* Compute CCR1 value to generate a duty cycle at 50% */
+    aSRC_Buffer[0] = (uint16_t) (((uint32_t) 5 * (uhTimerPeriod - 1)) / 10);
+    /* Compute CCR1 value to generate a duty cycle at 37.5% */
+    aSRC_Buffer[1] = (uint16_t) (((uint32_t) 375 * (uhTimerPeriod - 1)) / 1000);
+    /* Compute CCR1 value to generate a duty cycle at 25% */
+    aSRC_Buffer[2] = (uint16_t) (((uint32_t) 25 * (uhTimerPeriod - 1)) / 100);
+
+    /* TIM1 Peripheral Configuration -------------------------------------------*/
+    /* TIM1 clock enable */
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
+
+    /* Time Base configuration */
+
+    TIM_DeInit(TIM1);
+    TIM_TimeBaseStructure.TIM_Prescaler = 0;
+    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+    TIM_TimeBaseStructure.TIM_Period = uhTimerPeriod;
+    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
+
+    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
+
+    /* Channel 3 Configuration in PWM mode */
+
+    /* I think we just ned to enable channel 3 somehow, but without
+       (or optionally with) actual ouput to a GPIO pin.  */
+
+    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
+    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
+    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
+    TIM_OCInitStructure.TIM_Pulse = aSRC_Buffer[0];
+    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
+    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
+    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
+    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
+
+    TIM_OC3Init(TIM1, &TIM_OCInitStructure);
+
+    /* Enable preload feature */
+    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
+  
+    /* Automatic Output enable, Break, dead time and lock configuration*/
+    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
+    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
+    //TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
+    TIM_BDTRInitStructure.TIM_DeadTime = 11;
+    //TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
+    //TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
+    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
+
+    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
+
+    /* TIM1 counter enable */
+    TIM_Cmd(TIM1, ENABLE);
+  
+    /* Main Output Enable */
+    TIM_CtrlPWMOutputs(TIM1, ENABLE);
+}
+