From: baobrien Date: Sat, 7 Mar 2015 06:45:43 +0000 (+0000) Subject: Brady's first commit X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=660275622ad16bb548e6709684cc3ebe996cb5cb;p=freetel-svn-tracking.git Brady's first commit -IIR tner is fixed point -IIR tuner center changed to 700Khz -IIR Upconverter simulated in octave -STM32F4 DAC code copied and modified to support high sample rate on DAC1 (2Mhz) -Got a start on the C IIR Upconverter. Not tested yet. git-svn-id: https://svn.code.sf.net/p/freetel/code@2059 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/octave/dacres.m b/codec2-dev/octave/dacres.m new file mode 100644 index 00000000..155a65ae --- /dev/null +++ b/codec2-dev/octave/dacres.m @@ -0,0 +1,56 @@ +% dacres.m +% David Rowe 18 Feb 2015 +% Brady O'Brien 5 Mar 2015 +% DAC upconversion simulation + +graphics_toolkit ("gnuplot"); + + +M = 25; %interpolation +fs = 2E6/M; %Input sampling frequency +fb = 7E5; %Bandpass frequency + +f1 = fs/4; +f2 = f1 + 4E3; +f3 = f1 - 4E3; +t = (0:(fs-1)); + +beta1 = 0.999; +b1x = -2*sqrt(beta1)*cos(2*pi*fb/(fs*M)) +beta2 = 1 - (1-0.999)*M; + +s1 = [fs zeros(1,fs-1)]; % noise floor, continuous interferers +s2 = 100*4*cos(t*2*pi*f2/fs); % wanted signal 40dB above interferers +s3 = 100*3*cos(t*2*pi*f3/fs); % another wanted frequency +s4 = 100*4*cos(t*2*pi*f1/fs); % wanted signal at center frequency +s = s1 + s2 + s3 + s4; + + +s2 = filter([1 0 beta2],1,s); %pre interpolation notch filter to equalize bandpass after interpolation +s3 = zeros(1,length(s2)*M); %interpolate by zero-stuffing +s3(1:M:length(s2)*M) = s2; +s4 = filter(1,[1 b1x beta1],s3); %select wanted signal + +figure(1) +subplot(211) +plot(20*log10(abs(fft(s)/fs))) +grid +axis([0 fs/2 -10 50]) +title('Output from modem'); +subplot(212) +plot(20*log10(abs(fft(s2/fs)))) +grid +axis([0 fs/2 -10 70]) +title('After Pre-eq'); + +figure(2) +subplot(211) +plot(20*log10(abs(fft(s3)/fs))) +grid +axis([0 (fs/2)*M -10 80]) +title('After interpolation'); +subplot(212) +plot(20*log10(abs(fft(s4)/fs))) +grid +title('After bandpass'); +axis([0 (fs/2)*M -10 80]) diff --git a/codec2-dev/octave/octave-workspace b/codec2-dev/octave/octave-workspace new file mode 100644 index 00000000..e69de29b diff --git a/codec2-dev/src/codec2.c b/codec2-dev/src/codec2.c index 2f63d88f..08604a55 100644 --- a/codec2-dev/src/codec2.c +++ b/codec2-dev/src/codec2.c @@ -418,12 +418,11 @@ void codec2_decode_3200(struct CODEC2 *c2, short speech[], const unsigned char * interp_Wo(&model[0], &c2->prev_model_dec, &model[1]); e[0] = interp_energy(c2->prev_e_dec, e[1]); - + /* LSPs are sampled every 20ms so we interpolate the frame in between, then recover spectral amplitudes */ interpolate_lsp_ver2(&lsps[0][0], c2->prev_lsps_dec, &lsps[1][0], 0.5); - for(i=0; i<2; i++) { lsp_to_lpc(&lsps[i][0], &ak[i][0], LPC_ORD); aks_to_M2(c2->fft_fwd_cfg, &ak[i][0], LPC_ORD, &model[i], e[i], &snr, 0, 0, diff --git a/codec2-dev/src/postfilter.c b/codec2-dev/src/postfilter.c index fc88c0ea..f347658c 100644 --- a/codec2-dev/src/postfilter.c +++ b/codec2-dev/src/postfilter.c @@ -111,7 +111,7 @@ void postfilter( e = 1E-12; for(m=1; m<=model->L; m++) e += model->A[m]*model->A[m]; - + assert(e > 0.0); e = 10.0*log10f(e/model->L); diff --git a/codec2-dev/src/quantise.c b/codec2-dev/src/quantise.c index 10538041..03b9812e 100644 --- a/codec2-dev/src/quantise.c +++ b/codec2-dev/src/quantise.c @@ -941,9 +941,8 @@ void aks_to_M2( /* Determine power spectrum P(w) = E/(A(exp(jw))^2 ------------------------*/ - for(i=0; i. +*/ + +#ifndef __IIR_DUC_H +#define __IIR_DUC_H + +void iir_upconv(float modin[],unsigned short dac_out[]); + +#endif diff --git a/codec2-dev/stm32/inc/stm32f4_adc_tuner.h b/codec2-dev/stm32/inc/stm32f4_adc_tuner.h index 2db99fef..88f16a14 100644 --- a/codec2-dev/stm32/inc/stm32f4_adc_tuner.h +++ b/codec2-dev/stm32/inc/stm32f4_adc_tuner.h @@ -29,7 +29,7 @@ #ifndef __STM32F4_ADC_TUNER__ #define __STM32F4_ADC_TUNER__ -#define ADC_TUNER_M 45 /* decimation rate */ +#define ADC_TUNER_M 55 /* decimation rate */ #define ADC_TUNER_N 160 #define ADC_TUNER_BUF_SZ (ADC_TUNER_M*ADC_TUNER_N) diff --git a/codec2-dev/stm32/inc/stm32f4_dacduc.h b/codec2-dev/stm32/inc/stm32f4_dacduc.h new file mode 100644 index 00000000..580bfcc2 --- /dev/null +++ b/codec2-dev/stm32/inc/stm32f4_dacduc.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_dac.h + AUTHOR......: David Rowe + DATE CREATED: 1 June 2013 + + Two channel FIFO buffered DAC driver module for STM32F4. DAC1 is fixed at + Fs=2Mhz + +\*---------------------------------------------------------------------------*/ + +/* + 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 . +*/ + +#ifndef __STM32F4_DAC__ +#define __STM32F4_DAC__ + +#define DUC_N 100 +#define DUC_M 25 +#define DAC_DUC_BUF_SZ DUC_M*DUC_N +#define DAC_BUF_SZ 2048 + +void dac_open(int fifo_sz); +int dac1_write(short buf[], int n); /* DAC1 pin PA4 */ +int dac2_write(short buf[], int n); /* DAC2 pin PA5 */ + +#endif diff --git a/codec2-dev/stm32/src/fast_dac_ut.c b/codec2-dev/stm32/src/fast_dac_ut.c new file mode 100644 index 00000000..bc19547a --- /dev/null +++ b/codec2-dev/stm32/src/fast_dac_ut.c @@ -0,0 +1,56 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: dac_ut.c + AUTHOR......: David Rowe + DATE CREATED: May 31 2013 + + Plays a 500 Hz sine wave sampled at 16 kHz out of PA5 on a Discovery board, + or the speaker output of the SM1000. + +\*---------------------------------------------------------------------------*/ + +/* + 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 . +*/ + +#include +#include "stm32f4_dacduc.h" + +#define SINE_SAMPLES 60 + + +/* 32 sample sine wave which at Fs=16kHz will be 500Hz. Note samples + are 16 bit 2's complement, the DAC driver convertsto 12 bit + unsigned. */ + +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, + 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,}; + +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 +}; + +int main(void) { + + dac_open(4*DAC_DUC_BUF_SZ); + while (1) { + + /* keep DAC FIFOs topped up */ + + dac1_write((short*)aWave, SINE_SAMPLES); + } + +} + diff --git a/codec2-dev/stm32/src/iir_duc.c b/codec2-dev/stm32/src/iir_duc.c new file mode 100644 index 00000000..d4191717 --- /dev/null +++ b/codec2-dev/stm32/src/iir_duc.c @@ -0,0 +1,80 @@ + /*---------------------------------------------------------------------------*\ + + FILE........: iir_duc.c + AUTHOR......: Brady O'Brien + DATE CREATED: 6 Mar 2015 + + Interapolator/Filter for IF upconversion + + Unit testing: + + ~/codec2-dev/stm32$ gcc -D__UNITTEST__ -Iinc src/iir_tuner.c -o iir_tuner -lm -Wall + ~/codec2-dev/stm32$ ./iir_tuner + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 Brady O'Brien + + 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 . +*/ + +#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 +#define DAC_SCALE 4096 //Maximum output to DAC + + +/* + 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>B1SHFT) - ((B1MUL*n_2)>>B1SHFT); + n_2 = n_1; + n_1 = n; + dac_out[k]=(unsigned short)(n+DAC_SCALE/2); + } + } + +} + + + + + + diff --git a/codec2-dev/stm32/src/iir_tuner.c b/codec2-dev/stm32/src/iir_tuner.c index 334ff778..87d0ad2a 100644 --- a/codec2-dev/stm32/src/iir_tuner.c +++ b/codec2-dev/stm32/src/iir_tuner.c @@ -1,4 +1,4 @@ -/*---------------------------------------------------------------------------*\ + /*---------------------------------------------------------------------------*\ FILE........: iir_tuner.c AUTHOR......: David Rowe @@ -45,12 +45,23 @@ /* Filter coefficients of IIR tuner (BETA1) and FIR equaliser (BETA2). Note neat trick to relate BETA2 to BETA1 by the decimation rate */ -#define BETA1 0.999 -#define BETA2 (1.0 - (1.0-BETA1)*ADC_TUNER_M) +#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)*ADC_TUNER_M)// B2MUL/(2**B2SHFT) + +#define FIXED_IIR //Define this to compile a fixed point IIR filter /* filter states - we keep them global due to the need for speed */ +#ifdef FIXED_IIR +int n_2, n_1, o_2, o_1; +#else float y_2, y_1, z_2, z_1; +#endif /* ADC -> signed conversion - IIR BPF - Decimate - FIR Equaliser -> FIFO @@ -59,26 +70,40 @@ float y_2, y_1, z_2, z_1; void iir_tuner(float dec_50[], unsigned short adc_buf[]) { int i, j, k; float x, y, z; + int n, m, o; for(i=0, j=0; i>B1SHFT) - ((B1MUL*n_2)>>B1SHFT); + n_2 = n_1; + n_1 = n; + #else + x = (int)adc_buf[i] - 32768; + y = x - (BETA1*y_2); + y_2 = y_1; y_1 = y; + #endif } /* Equaliser FIR filter, notch at Fs/(4*ADC_TUNER_M) to smooth out IIR BPF passband response */ - - z = y + BETA2*z_2; - dec_50[j] = z; + #ifdef FIXED_IIR + o = n + ((B2MUL*o_2)>>B2SHFT); + dec_50[j] = (float)o; + o_2 = o_1; + o_1 = n; + #else + z=y+BETA2*z_2; + dec_50[j] = z; z_2 = z_1; z_1 = y; + #endif + } } @@ -133,7 +158,7 @@ int main(void) { /* test Fs=2E6 unsigned short to Fs=50E3 float tuner/resampler -----------------------*/ - f1 = 500E3; + f1 = 700E3; f2 = f1 + 8E3; /* wanted */ f3 = f1 - 7E3; /* wanted */ f4 = f1 - 207E3; /* out of band, should be greatly attenuated */ diff --git a/codec2-dev/stm32/src/stm32f4_dacduc.c b/codec2-dev/stm32/src/stm32f4_dacduc.c new file mode 100644 index 00000000..e1b231ab --- /dev/null +++ b/codec2-dev/stm32/src/stm32f4_dacduc.c @@ -0,0 +1,422 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_dac.c + AUTHOR......: David Rowe + DATE CREATED: 1 June 2013 + + DAC driver module for STM32F4. DAC1 if fixed at Fs of 2Mhz. + +\*---------------------------------------------------------------------------*/ + +/* + 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 . +*/ + +#include +#include +#include +#include "stm32f4xx.h" +#include "codec2_fifo.h" +#include "stm32f4_dacduc.h" +#include "debugblinky.h" + +/* write to these registers for 12 bit left aligned data, as per data sheet + make sure 4 least sig bits set to 0 */ + +#define DAC_DHR12R1_ADDRESS 0x40007408 +#define DAC_DHR12R2_ADDRESS 0x40007414 + +#define DAC_MAX 4096 /* maximum amplitude */ + +/* y=mx+c mapping of samples16 bit shorts to DAC samples. Table: 74 + of data sheet indicates With DAC buffer on, DAC range is limited to + 0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close. + */ + +#define M ((3868.0-224.0)/65536.0) +#define C 2047.0 + + +static struct FIFO *dac1_fifo; +static struct FIFO *dac2_fifo; + +static unsigned short dac1_buf[DAC_DUC_BUF_SZ]; +static unsigned short dac2_buf[DAC_BUF_SZ]; + +static void tim6_config(void); +static void tim7_config(void); +static void dac1_config(void); +static void dac2_config(void); + +int dac_underflow; + +void dac_open(int fifo_size) { + + memset(dac1_buf, 32768, sizeof(short)*DAC_DUC_BUF_SZ); + memset(dac2_buf, 32768, sizeof(short)*DAC_BUF_SZ); + + /* Create fifos */ + + dac1_fifo = fifo_create(fifo_size); + dac2_fifo = fifo_create(fifo_size); + assert(dac1_fifo != NULL); + assert(dac2_fifo != NULL); + + /* Turn on the clocks we need -----------------------------------------------*/ + + /* DMA1 clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); + /* GPIOA clock enable (to be used with DAC) */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + /* DAC Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); + + /* GPIO Pin configuration DAC1->PA.4, DAC2->PA.5 configuration --------------*/ + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Timer and DAC 1 & 2 Configuration ----------------------------------------*/ + tim7_config(); + tim6_config(); + dac1_config(); + dac2_config(); + + init_debug_blinky(); +} + + +/* Call these puppies to send samples to the DACs. For your + convenience they accept signed 16 bit samples. */ + +int dac1_write(short buf[], int n) { + return fifo_write(dac1_fifo, buf, n); +} + +int dac2_write(short buf[], int n) { + return fifo_write(dac2_fifo, buf, n); +} + +static void tim6_config(void) +{ + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + + /* TIM6 Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); + + /* -------------------------------------------------------- + + TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since + APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig + 13 clock tree figure in DM0031020.pdf). + + Sample rate Fs = 2*PCLK1/TIM_ClockDivision + = (HCLK/2)/TIM_ClockDivision + + ----------------------------------------------------------- */ + + /* Time base configuration */ + + TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); + TIM_TimeBaseStructure.TIM_Period = 80; + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); + + /* TIM6 TRGO selection */ + + TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); + + /* TIM6 enable counter */ + + TIM_Cmd(TIM6, ENABLE); +} + +/* Sets up tim7 to run at a high sample rate */ +void tim7_config(void) +{ + /* Set up tim7 */ + + + TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; + + /* TIM7 Periph clock enable */ + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE); + + /* -------------------------------------------------------- + + + TIM7 input clock (TIM7CLK) is set to 2 * APB1 clock (PCLK1), since + APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig + 13 clock tree figure in DM0031020.pdf). + + Sample rate Fs = 2*PCLK1/TIM_ClockDivision + = (HCLK/2)/TIM_ClockDivision + + ----------------------------------------------------------- */ + + /* Time base configuration */ + + TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); + TIM_TimeBaseStructure.TIM_Period = 41; + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure); + + /* TIM7 TRGO selection */ + + TIM_SelectOutputTrigger(TIM7, TIM_TRGOSource_Update); + + /* TIM7 enable counter */ + + TIM_Cmd(TIM7, ENABLE); +} + +static void dac1_config(void) +{ + DAC_InitTypeDef DAC_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + /* DAC channel 1 Configuration */ + + /* + This line fixed a bug that cost me 5 days, bad wave amplitude + value, and some STM32F4 periph library bugs caused triangle wave + geneartion to be enable resulting in a low level tone on the + SM1000, that we thought was caused by analog issues like layour + or power supply biasing + */ + DAC_StructInit(&DAC_InitStructure); + + DAC_InitStructure.DAC_Trigger = DAC_Trigger_T7_TRGO; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(DAC_Channel_1, &DAC_InitStructure); + + /* DMA1_Stream5 channel7 configuration **************************************/ + /* Table 35 page 219 of the monster data sheet */ + + DMA_DeInit(DMA1_Stream5); + DMA_InitStructure.DMA_Channel = DMA_Channel_7; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = DAC_DUC_BUF_SZ; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(DMA1_Stream5, &DMA_InitStructure); + + /* Enable DMA Half & Complete interrupts */ + + DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE); + + /* Enable the DMA Stream IRQ Channel */ + + NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + /* Enable DMA1_Stream5 */ + + DMA_Cmd(DMA1_Stream5, ENABLE); + + /* Enable DAC Channel 1 */ + + DAC_Cmd(DAC_Channel_1, ENABLE); + + /* Enable DMA for DAC Channel 1 */ + + DAC_DMACmd(DAC_Channel_1, ENABLE); +} + +static void dac2_config(void) +{ + DAC_InitTypeDef DAC_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + NVIC_InitTypeDef NVIC_InitStructure; + + /* DAC channel 2 Configuration (see notes in dac1_config() above) */ + + DAC_StructInit(&DAC_InitStructure); + DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; + DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; + DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; + DAC_Init(DAC_Channel_2, &DAC_InitStructure); + + /* DMA1_Stream6 channel7 configuration **************************************/ + + DMA_DeInit(DMA1_Stream6); + DMA_InitStructure.DMA_Channel = DMA_Channel_7; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac2_buf; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; + DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; + DMA_InitStructure.DMA_Priority = DMA_Priority_High; + DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; + DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + DMA_Init(DMA1_Stream6, &DMA_InitStructure); + + /* Enable DMA Half & Complete interrupts */ + + DMA_ITConfig(DMA1_Stream6, DMA_IT_TC | DMA_IT_HT, ENABLE); + + /* Enable the DMA Stream IRQ Channel */ + + NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + + /* Enable DMA1_Stream6 */ + + DMA_Cmd(DMA1_Stream6, ENABLE); + + /* Enable DAC Channel 2 */ + + DAC_Cmd(DAC_Channel_2, ENABLE); + + /* Enable DMA for DAC Channel 2 */ + + DAC_DMACmd(DAC_Channel_2, ENABLE); + +} + +/******************************************************************************/ +/* STM32F4xx Peripherals Interrupt Handlers */ +/* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ +/* available peripheral interrupt handler's name please refer to the startup */ +/* file (startup_stm32f40xx.s/startup_stm32f427x.s). */ +/******************************************************************************/ + +/* + This function handles DMA1 Stream 5 interrupt request for DAC1. +*/ + +void DMA1_Stream5_IRQHandler(void) { + GPIOE->ODR |= (1 << 1); + + /* Transfer half empty interrupt - refill first half */ + + if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) { + /* fill first half from fifo */ + + if (fifo_read(dac1_fifo, (short*)dac1_buf, DAC_DUC_BUF_SZ/2) == -1) { + memset(dac1_buf, 0, sizeof(short)*DAC_DUC_BUF_SZ/2); + dac_underflow++; + } + + /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5); + } + + /* Transfer complete interrupt - refill 2nd half */ + + if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) { + /* fill second half from fifo */ + + if (fifo_read(dac1_fifo, (short*)(dac1_buf+DAC_DUC_BUF_SZ/2), DAC_DUC_BUF_SZ/2) == -1) { + memset(dac1_buf, 0, sizeof(short)*DAC_DUC_BUF_SZ/2); + dac_underflow++; + } /* Clear DMA Stream Transfer Complete interrupt pending bit */ + + DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5); + } + + GPIOE->ODR &= ~(1 << 1); +} + +/* + This function handles DMA1 Stream 6 interrupt request for DAC2. +*/ + +void DMA1_Stream6_IRQHandler(void) { + int i, j, sam; + short signed_buf[DAC_BUF_SZ/2]; + + GPIOE->ODR |= (1 << 2); + + /* Transfer half empty interrupt - refill first half */ + + if(DMA_GetITStatus(DMA1_Stream6, DMA_IT_HTIF6) != RESET) { + /* fill first half from fifo */ + + if (fifo_read(dac2_fifo, signed_buf, DAC_BUF_SZ/2) == -1) { + memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2); + dac_underflow++; + } + + /* convert to unsigned */ + + for(i=0; iODR &= ~(1 << 2); +} +