*/\r
\r
#include <assert.h>\r
+#include <stdlib.h>\r
#include "stm32f4_dacduc.h"\r
+#include "iir_duc.h"\r
+#include "stm32f4xx.h"\r
+#include <stm32f4xx_tim.h>\r
+#include <stm32f4xx_rcc.h>\r
+#include "gdb_stdio.h"\r
\r
-#define SINE_SAMPLES 60\r
+#define SINE_SAMPLES 32\r
\r
\r
/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples\r
short aWave[] = {4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,\r
4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,4095,0,};\r
\r
-short aSine[] = {390, 3981, 1410, 841, 4080, 841, 1410, 3981, 390, 2040, 3691, 100, 2671, 3240, 0, 3240, 2671, 100, 3691, 2040, 390, 3981, 1410, 841, 4080, 841, 1410, 3981, 390, 2040, 3691, 100, 2671, 3240, 0, 3240, 2671, 100, 3691, 2040,390, 3981, 1410, 841, 4080, 841, 1410, 3981, 390, 2040, 3691, 100, 2671, 3240, 0, 3240, 2671, 100, 3691, 2040\r
+short aSine[] = {1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1601, 0, 1600, 3200, 1600, 0, 1600, 3200, 1601, 0\r
};\r
\r
+//Sine at Fs/4\r
+float f4sine[] = {1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,\r
+ -1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,\r
+ 1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,\r
+ -1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,1,0,-1,0,};\r
+\r
+unsigned short outbuf[DAC_DUC_BUF_SZ];\r
+\r
+void setup_timer()\r
+{\r
+ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);\r
+\r
+ TIM_TimeBaseInitTypeDef timerInitStructure; \r
+ timerInitStructure.TIM_Prescaler = 84;\r
+ timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;\r
+ timerInitStructure.TIM_Period = 0x8FFFFFFF;\r
+ timerInitStructure.TIM_ClockDivision = 0;\r
+ timerInitStructure.TIM_RepetitionCounter = 0;\r
+ TIM_TimeBaseInit(TIM2, &timerInitStructure);\r
+ TIM_Cmd(TIM2, ENABLE);\r
+}\r
+\r
int main(void) {\r
+ int tstart,tend,cyc;\r
\r
- dac_open(4*DAC_DUC_BUF_SZ);\r
- while (1) {\r
+ memset((void*)outbuf,0,sizeof(short)*DAC_DUC_BUF_SZ);\r
+ setup_timer();\r
+ dac_open(2*DAC_DUC_BUF_SZ,2*DAC_BUF_SZ);\r
\r
+ tstart=tend=0;\r
+ while (1) {\r
+ cyc++;\r
+ if(cyc%100000==0){\r
+ printf("upconvert takes %d uSecs\n",tend-tstart);\r
+ }\r
/* keep DAC FIFOs topped up */\r
-\r
- dac1_write((short*)aWave, SINE_SAMPLES);\r
+ tstart = TIM_GetCounter(TIM2);\r
+ iir_upconv(f4sine,outbuf);\r
+ tend = TIM_GetCounter(TIM2);\r
+ dac1_write((short*)outbuf,DAC_DUC_BUF_SZ);\r
}\r
\r
}\r
Unit testing:
- ~/codec2-dev/stm32$ gcc -D__UNITTEST__ -Iinc src/iir_tuner.c -o iir_tuner -lm -Wall
- ~/codec2-dev/stm32$ ./iir_tuner
+ ~/codec2-dev/stm32$ gcc -D__UNITTEST__ -Iinc src/iir_duc.c -o iir_duc -lm -Wall
+ ~/codec2-dev/stm32$ ./iir_duc
\*---------------------------------------------------------------------------*/
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#define BETA1 .9990234375 // B1MUL/(2**B1SHFT)
-#define B1MUL 1023
-#define B1SMUL 1204
-#define B1SHFT 10 // 10 bits gives us plenty of headroom between 31 bits of int and 14 bits of ADC
-#define B2MUL 979 // This actually matches BETA2 exactly with the supplied BETA1
-#define B2SHFT 10 // 10 is also the lowest we can go without beta1=1
-#define BETA2 (1.0 - (1.0-BETA1)*DUC_M)// B2MUL/(2**B2SHFT)
-#define IN_SCALE 1.0 //Input scaling factor
+#include "stm32f4_dacduc.h"
+#include "iir_duc.h"
+
+#define BETA1 0.99002 // B1MUL/(2**B1SHFT)
+#define B1MUL 32441
+#define B1SMUL -38328
+#define B1SHFT 15 // 10 bits gives us plenty of headroom between 31 bits of int and 14 bits of ADC
+#define B2MUL 24593 // This actually matches BETA2 exactly with the supplied BETA1
+#define B2SHFT 15 // 10 is also the lowest we can go without beta1=1
+#define BETA2 (1.0 - (1.0-BETA1)*DUC_M) // B2MUL/(2**B2SHFT)
+#define IN_SCALE 2.0 //Input scaling factor. Should be as large as the amplitude of the incoming samples
#define DAC_SCALE 4096 //Maximum output to DAC
+#define DAC_SCALE_2 2040
+//IIR and FIR filter states. Global for go fast.
+float f_1,f_2,f;
+int n_1,n_2,n;
+
/*
Upconvert and bandpass filter a chunk of spectrum from Fs/M to Fs. We're going for 700khz here.
modin needs to be DUC_N long and dac_out needs to be DUC_N*DUC_M long. This
*/
-float f_1,f_2,f;
-int n_1,n_2,n;
-int dac_temp[DUC_N*DUC_M]; //Temporary storage for samples before IIR.
-
-void iir_upconv(float modin[],unsigned short dac_out[]){
- memset((void*)dac_temp,0,sizeof(int)*DUC_N*DUC_M); //Preset output array for interpolation
- int i,j,k;
- int m;
- k=0;
- //Iterate through input samples and apply pre-eq FIR, interpolate, and apply BPF IIR
- for(i=0;i<DUC_N;i++){
- f = modin[i]+f_2*BETA2;
- f_1 = modin[i];
- f_2 = f_1;
- //m = (int)(f/(IN_SCALE*2))*DAC_SCALE; //Scale and convert to int. I probably should add more bits here and truncate before DAC.
- m = (int)((f/(IN_SCALE*2))*DAC_SCALE);
- dac_temp[k]= m;
- for(j=0;j<DUC_M;j++,k++){
- n = dac_temp[k] - ((B1SMUL*n_1)>>B1SHFT) - ((B1MUL*n_2)>>B1SHFT);
+void iir_upconv(float modin[], unsigned short dac_out[]){
+ int i,j,k;
+ int m;
+ k=0;
+ //Iterate through input samples and apply pre-eq FIR, interpolate, and apply BPF IIR
+ for(i=0;i<DUC_N;i++){
+ f = modin[i]+f_2*BETA2;
+ f_2 = f_1;
+ f_1 = modin[i]; //Scale fir output and convert to fixed.
+ m = (int)((f/(IN_SCALE))*DAC_SCALE_2); //Scale fir output and convert to fixed
+ n = (m) + ((B1SMUL*n_1)>>B1SHFT) - ((B1MUL*n_2)>>B1SHFT); //Apply one cycle of IIR. This feeds the fir-ed sample into the output filter
+ n_2 = n_1;
+ n_1 = n;
+ dac_out[k]=(unsigned short)(n+DAC_SCALE_2);
+ k++;
+ //now do the rest of the filtering. Because we're zero-stuffing we can neglect the sample from the fir filter.
+ for(j=1;j<DUC_M;j++,k++){
+ n = ((B1SMUL*n_1)>>B1SHFT) - ((B1MUL*n_2)>>B1SHFT);
n_2 = n_1;
n_1 = n;
- dac_out[k]=(unsigned short)(n+DAC_SCALE/2);
- }
- }
-
+ dac_out[k]=(unsigned short)((n)+DAC_SCALE_2);
+ }
+ }
}
+#ifdef __UNITTEST__
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#define FS 80000
+#define AMP_MAX 1
+
+#define NOUT_BUFS 401
+#define NIN (NOUT_BUFS*DUC_N)
+#define NOUT (NIN*DUC_M)
+
+void synth_line(float us[], float f, float amp, int n) {
+ float w, sam;
+ int i;
+
+ w = 2*M_PI*f/(float)FS;
+
+ for(i=0; i<n; i++) {
+ sam = amp*AMP_MAX*cos(w*i);
+ us[i] += sam;
+ }
+}
+
+float s[NIN];
+float fout[NIN];
+unsigned short todac[NOUT];
+
+int main(void) {
+ float f1,f2,f3;
+ FILE *f;
+ int i;
+
+ f1 = 20E3; /* center of passband */
+ f2 = f1; /* wanted */
+ f3 = f1 + 7E3; /* wanted */
+
+
+ for(i=0; i<NIN; i++)
+ s[i] = 0.01;
+ synth_line(s, f2, 0.5, NIN);
+ synth_line(s, f3, 0.5, NIN);
+ for(i=0;i<NOUT_BUFS;i++)
+ iir_upconv(&s[i*(DUC_N)],&todac[i*(DUC_N*DUC_M)]);
+
+ f = fopen("iir_duc_s.txt", "wt"); assert(f != NULL);
+ for(i=DUC_N; i<NIN; i++)
+ fprintf(f, "%f\n", s[i]);
+ fprintf(f, "\n");
+ fclose(f);
+
+ f = fopen("iir_duc_f.txt", "wt"); assert(f != NULL);
+ for(i=DUC_N; i<NIN; i++)
+ fprintf(f, "%f\n", fout[i]);
+ fprintf(f, "\n");
+ fclose(f);
+
+ f = fopen("iir_duc.txt", "wt"); assert(f != NULL);
+ for(i=DUC_N*DUC_M; i<NOUT; i++)
+ fprintf(f, "%d\n", todac[i]);
+ fprintf(f, "\n");
+ fclose(f);
+
+ return 0;
+}
+#endif
#include "codec2_fifo.h"\r
#include "stm32f4_dacduc.h"\r
#include "debugblinky.h"\r
-\r
+ \r
/* write to these registers for 12 bit left aligned data, as per data sheet \r
make sure 4 least sig bits set to 0 */\r
\r
\r
int dac_underflow;\r
\r
-void dac_open(int fifo_size) {\r
+void fast_dac_open(int dac1_fifo_size,int dac2_fifo_size) {\r
\r
memset(dac1_buf, 32768, sizeof(short)*DAC_DUC_BUF_SZ);\r
memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ);\r
\r
/* Create fifos */\r
\r
- dac1_fifo = fifo_create(fifo_size);\r
- dac2_fifo = fifo_create(fifo_size);\r
+ dac1_fifo = fifo_create(dac1_fifo_size);\r
+ dac2_fifo = fifo_create(dac2_fifo_size);\r
assert(dac1_fifo != NULL);\r
assert(dac2_fifo != NULL);\r
\r
/* Time base configuration */\r
\r
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); \r
- TIM_TimeBaseStructure.TIM_Period = 80; \r
+ TIM_TimeBaseStructure.TIM_Period = 5250; \r
TIM_TimeBaseStructure.TIM_Prescaler = 0; \r
TIM_TimeBaseStructure.TIM_ClockDivision = 0; \r
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; \r
\r
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO; \r
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;\r
- DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;\r
+\r
+ /*External buffering is needed to get nice square samples at Fs=2Mhz. See DM00129215.pdf */\r
+ DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;\r
DAC_Init(DAC_Channel_1, &DAC_InitStructure);\r
\r
/* DMA1_Stream5 channel7 configuration **************************************/\r
\r
if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) {\r
/* fill first half from fifo */\r
- \r
- if (fifo_read(dac1_fifo, (short*)dac1_buf, DAC_DUC_BUF_SZ/2) == -1) {\r
- memset(dac1_buf, 0, sizeof(short)*DAC_DUC_BUF_SZ/2);\r
- dac_underflow++;\r
- }\r
+ fifo_read(dac1_fifo, (short*)dac1_buf, DAC_DUC_BUF_SZ/2);\r
\r
/* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5); \r
}\r
\r
\r
if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) {\r
/* fill second half from fifo */\r
+ fifo_read(dac1_fifo, (short*)(dac1_buf+DAC_DUC_BUF_SZ/2), DAC_DUC_BUF_SZ/2);\r
\r
- if (fifo_read(dac1_fifo, (short*)(dac1_buf+DAC_DUC_BUF_SZ/2), DAC_DUC_BUF_SZ/2) == -1) {\r
- memset(dac1_buf, 0, sizeof(short)*DAC_DUC_BUF_SZ/2);\r
- dac_underflow++;\r
- } /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
-\r
+ /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5); \r
}\r
\r