From 0b8d9ff9c06835b9b6a4588ccbb50b484849dded Mon Sep 17 00:00:00 2001 From: drowe67 Date: Fri, 4 Jul 2014 22:34:21 +0000 Subject: [PATCH] various changes for STM32F4 file used during SM1000 prototyping git-svn-id: https://svn.code.sf.net/p/freetel/code@1736 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/stm32/Makefile | 1 + codec2-dev/stm32/src/machdep.h | 51 ++ codec2-dev/stm32/src/power_ut.c | 135 +++++ codec2-dev/stm32/src/sine.c | 648 ++++++++++++++++++++++++ codec2-dev/stm32/src/sine.h | 48 ++ codec2-dev/stm32/src/stm32f4_pwm.c | 15 +- codec2-dev/stm32/src/system_stm32f4xx.c | 4 +- codec2-dev/stm32/src/timer_ut.c | 179 +++++++ 8 files changed, 1077 insertions(+), 4 deletions(-) create mode 100644 codec2-dev/stm32/src/machdep.h create mode 100644 codec2-dev/stm32/src/power_ut.c create mode 100644 codec2-dev/stm32/src/sine.c create mode 100644 codec2-dev/stm32/src/sine.h create mode 100644 codec2-dev/stm32/src/timer_ut.c diff --git a/codec2-dev/stm32/Makefile b/codec2-dev/stm32/Makefile index 0288407a..dbda50e0 100644 --- a/codec2-dev/stm32/Makefile +++ b/codec2-dev/stm32/Makefile @@ -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 index 00000000..ef2e6494 --- /dev/null +++ b/codec2-dev/stm32/src/machdep.h @@ -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 . +*/ + +#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 index 00000000..c094aef8 --- /dev/null +++ b/codec2-dev/stm32/src/power_ut.c @@ -0,0 +1,135 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: power_ut.c + AUTHOR......: David Rowe + DATE CREATED: 30 May 2014 + + Runs Codec 2, ADC, and DAC, to fully exercise STM32C so we can a feel for + run-time power consumption for SmartMic and hence dimension regulators. + +\*---------------------------------------------------------------------------*/ + +/* + 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 . +*/ + +#include +#include +#include +#include + +#include "stm32f4xx_conf.h" +#include "stm32f4xx.h" +#include "stm32f4_adc.h" +#include "stm32f4_dac.h" +#include "gdb_stdio.h" +#include "codec2.h" +#include "dump.h" +#include "sine.h" +#include "machdep.h" + +#ifdef __EMBEDDED__ +#define printf gdb_stdio_printf +#define fopen gdb_stdio_fopen +#define fclose gdb_stdio_fclose +#define fread gdb_stdio_fread +#define fwrite gdb_stdio_fwrite +#endif + +#define SPEED_TEST_SAMPLES 24000 + +/* modifiaction of test used to measure codec2 execuation speed. We read/write ADC/DAC + but dont do anything with the samples, as they are at 16 kHz and codec needs 8 kHz. Just + trying to exercise everything to get a feel for power consumption */ + +static void c2speedtest(int mode, char inputfile[]) +{ + struct CODEC2 *codec2; + short *inbuf, *outbuf, *pinbuf, *dummy_buf; + unsigned char *bits; + int nsam, nbit, nframes; + FILE *fin; + int f, nread; + + codec2 = codec2_create(mode); + nsam = codec2_samples_per_frame(codec2); + nframes = SPEED_TEST_SAMPLES/nsam; + outbuf = (short*)malloc(nsam*sizeof(short)); + inbuf = (short*)malloc(SPEED_TEST_SAMPLES*sizeof(short)); + nbit = codec2_bits_per_frame(codec2); + bits = (unsigned char*)malloc(nbit*sizeof(char)); + dummy_buf = (short*)malloc(2*nsam*sizeof(short)); + + fin = fopen(inputfile, "rb"); + if (fin == NULL) { + printf("Error opening input file: %s\nTerminating....\n",inputfile); + exit(1); + } + + printf("reading samples ....\n"); + nread = fread(inbuf, sizeof(short), SPEED_TEST_SAMPLES, fin); + if (nread != SPEED_TEST_SAMPLES) { + printf("error reading %s, %d samples reqd, %d read\n", + inputfile, SPEED_TEST_SAMPLES, nread); + } + fclose(fin); + + pinbuf = inbuf; + for(f=0; fODR = (1 << 13); + codec2_encode(codec2, bits, pinbuf); + pinbuf += nsam; + GPIOD->ODR &= ~(1 << 13); + //printf("Codec 2 dec\n"); + codec2_decode(codec2, outbuf, bits); + + //printf("write to DAC\n"); + while(dac_write(dummy_buf, nsam*2) == -1); /* runs at Fs = 16kHz */ + //printf("."); + } + + free(inbuf); + free(outbuf); + free(bits); + codec2_destroy(codec2); +} + +void gpio_init() { + RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // enable the clock to GPIOD + GPIOD->MODER = (1 << 26); // set pin 13 to be general + // purpose output +} + +int main(int argc, char *argv[]) { + SystemInit(); + gpio_init(); + machdep_timer_init (); + adc_open(); + dac_open(); + + printf("Starting power_ut\n"); + + c2speedtest(CODEC2_MODE_1600, "stm_in.raw"); + + printf("Finished\n"); + + return 0; +} + diff --git a/codec2-dev/stm32/src/sine.c b/codec2-dev/stm32/src/sine.c new file mode 100644 index 00000000..254a61ec --- /dev/null +++ b/codec2-dev/stm32/src/sine.c @@ -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 . +*/ + +/*---------------------------------------------------------------------------*\ + + INCLUDES + +\*---------------------------------------------------------------------------*/ + +#include +#include +#include + +#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; iWo + 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; iA[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; iWo; + 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 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 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; iA[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. +*/ + +#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 diff --git a/codec2-dev/stm32/src/stm32f4_pwm.c b/codec2-dev/stm32/src/stm32f4_pwm.c index 340d8beb..776baf54 100644 --- a/codec2-dev/stm32/src/stm32f4_pwm.c +++ b/codec2-dev/stm32/src/stm32f4_pwm.c @@ -31,6 +31,7 @@ #include #include #include +#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. +*/ + +#include +#include +#include + +#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); +} + -- 2.25.1