From 6dd32abad76b9beb274668415901191b9112cfb3 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Fri, 6 Nov 2015 01:15:40 +0000 Subject: [PATCH] merged Stuarts latest, compiles OK, haven't tested git-svn-id: https://svn.code.sf.net/p/freetel/code@2481 01035d8c-6547-0410-b346-abe4f91aad63 --- codec2-dev/stm32/Makefile | 32 ++- codec2-dev/stm32/inc/stm32f4_adc_tuner.h | 2 +- codec2-dev/stm32/inc/stm32f4_usb_vcp.h | 1 + codec2-dev/stm32/src/adc_sfdr_ut.c | 1 + codec2-dev/stm32/src/codec2_profile.c | 1 - codec2-dev/stm32/src/dac_ut.c | 1 + codec2-dev/stm32/src/fast_dac_ut.c | 1 - codec2-dev/stm32/src/gdb_stdio.c | 2 +- codec2-dev/stm32/src/iir_tuner.c | 12 +- codec2-dev/stm32/src/stm32f4_adc_tuner.c | 53 +++-- codec2-dev/stm32/src/stm32f4_dac.c | 1 - codec2-dev/stm32/src/stm32f4_dacloduc.c | 276 +++++++++++++++++++++++ codec2-dev/stm32/src/usb_vcp_ut.c | 66 ++++-- 13 files changed, 385 insertions(+), 64 deletions(-) create mode 100644 codec2-dev/stm32/src/stm32f4_dacloduc.c diff --git a/codec2-dev/stm32/Makefile b/codec2-dev/stm32/Makefile index a2a0248d..537fccd0 100644 --- a/codec2-dev/stm32/Makefile +++ b/codec2-dev/stm32/Makefile @@ -436,8 +436,6 @@ SRCS += src/startup_stm32f4xx.s src/init.c OBJS = $(SRCS:.c=.o) -################################################### - all: codec2_profile.bin fft_test.bin dac_ut.bin dac_play.bin adc_rec.bin pwm_ut.bin fdmdv_profile.bin sm1000_leds_switches_ut.bin sm1000.bin adcdac_ut.bin freedv_tx_profile.bin freedv_rx_profile.bin adc_sd.bin usb_vcp_ut.bin tuner_ut.bin fast_dac_ut.bin adc_sfdr_ut.bin # Rule for making directories automatically. @@ -633,7 +631,7 @@ src/init.c USB_VCP_UT+=$(USB_VCP) -CFLAGS += -Iusb_conf -Iusb_lib/cdc -Iusb_lib/core -Iusb_lib/otg +CFLAGS += -DUSE_USB_OTG_FS -DUSE_ULPI_PHY -Iusb_conf -Iusb_lib/cdc -Iusb_lib/core -Iusb_lib/otg usb_vcp_ut.elf: $(USB_VCP_UT:.c=.o) libstm32f4.a $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) @@ -774,15 +772,33 @@ adc_sfdr_ut.elf: $(ADC_SFDR_UT_SRCS:.c=.O3.o) src/stm32f4_adc_tuner.o \ libstm32f4.a $(CC) $(CFLAGS) -O3 $^ -o $@ $(LIBPATHS) $(LIBS) -# --------------------------------------------------------------------------------- -clean: - rm -f *.elf *.bin - rm -f libstm32f4.a - find . ../src -type f -name '*.o' | xargs rm -f + +FM_LODUC_PLAY_SRCS=\ +src/fm_loduc_play.c \ +gdb_stdio.c \ +../src/fifo.c \ +../src/fm.c \ +src/debugblinky.c \ +src/system_stm32f4xx.c \ +src/startup_stm32f4xx.s \ +src/init.c + +src/stm32f4_dacloduc.o: src/stm32f4_dacloduc.c + $(CC) $(CFLAGS) $^ -c -o $@ + +fm_loduc_play.elf: $(FM_LODUC_PLAY_SRCS) src/stm32f4_dacloduc.o + $(CC) $(CFLAGS) -O3 $^ -o $@ $(LIBPATHS) $(LIBS) # --------------------------------------------------------------------------------- # Objects that require the peripheral library src/sm1000_main.o: $(PERIPHLIBDIR)/.unpack src/codec2_profile.o: $(PERIPHLIBDIR)/.unpack + +# --------------------------------------------------------------------------------- + +clean: + rm -f *.elf *.bin + rm -f libstm32f4.a + find . ../src -type f -name '*.o' | xargs rm -f diff --git a/codec2-dev/stm32/inc/stm32f4_adc_tuner.h b/codec2-dev/stm32/inc/stm32f4_adc_tuner.h index 6c7c7559..a258b9d8 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 55 /* decimation rate */ +#define ADC_TUNER_M 45 /* 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_usb_vcp.h b/codec2-dev/stm32/inc/stm32f4_usb_vcp.h index 384f3f0b..d742ebc1 100644 --- a/codec2-dev/stm32/inc/stm32f4_usb_vcp.h +++ b/codec2-dev/stm32/inc/stm32f4_usb_vcp.h @@ -19,5 +19,6 @@ int VCP_get_char(uint8_t *buf); int VCP_get_string(uint8_t *buf); void VCP_put_char(uint8_t buf); void VCP_send_str(uint8_t* buf); +void VCP_send_buffer(uint8_t* buf, int len); #endif diff --git a/codec2-dev/stm32/src/adc_sfdr_ut.c b/codec2-dev/stm32/src/adc_sfdr_ut.c index 21853b46..952ecef0 100644 --- a/codec2-dev/stm32/src/adc_sfdr_ut.c +++ b/codec2-dev/stm32/src/adc_sfdr_ut.c @@ -88,3 +88,4 @@ int main(void) { printf("Finished!\n"); } +>>>>>>> .r2480 diff --git a/codec2-dev/stm32/src/codec2_profile.c b/codec2-dev/stm32/src/codec2_profile.c index 73ca7247..5537bad5 100644 --- a/codec2-dev/stm32/src/codec2_profile.c +++ b/codec2-dev/stm32/src/codec2_profile.c @@ -179,4 +179,3 @@ int main(int argc, char *argv[]) { return 0; } - diff --git a/codec2-dev/stm32/src/dac_ut.c b/codec2-dev/stm32/src/dac_ut.c index 872ecf68..f38d72de 100644 --- a/codec2-dev/stm32/src/dac_ut.c +++ b/codec2-dev/stm32/src/dac_ut.c @@ -57,3 +57,4 @@ int main(void) { } +>>>>>>> .r2480 diff --git a/codec2-dev/stm32/src/fast_dac_ut.c b/codec2-dev/stm32/src/fast_dac_ut.c index 9712c441..e9b50f8f 100644 --- a/codec2-dev/stm32/src/fast_dac_ut.c +++ b/codec2-dev/stm32/src/fast_dac_ut.c @@ -112,4 +112,3 @@ int main(void) { } } - diff --git a/codec2-dev/stm32/src/gdb_stdio.c b/codec2-dev/stm32/src/gdb_stdio.c index ef7e12a1..46245e4c 100644 --- a/codec2-dev/stm32/src/gdb_stdio.c +++ b/codec2-dev/stm32/src/gdb_stdio.c @@ -44,7 +44,7 @@ /* globals we use to communicate with host */ volatile int gdb_stdio_func = 0; -volatile int gdb_stdio_ret = 0; +volatile int gdb_stdio_ret; volatile char *gdb_stdio_pstr1; volatile char *gdb_stdio_pstr2; volatile int gdb_stdio_strlen1; diff --git a/codec2-dev/stm32/src/iir_tuner.c b/codec2-dev/stm32/src/iir_tuner.c index c92d352f..2baae590 100644 --- a/codec2-dev/stm32/src/iir_tuner.c +++ b/codec2-dev/stm32/src/iir_tuner.c @@ -67,7 +67,11 @@ float y_2, y_1, z_2, z_1; ADC -> signed conversion - IIR BPF - Decimate - FIR Equaliser -> FIFO */ -void iir_tuner(float dec_50[], unsigned short adc_buf[]) { +void iir_tuner( + float dec_50[], // ADC_TUNER_N/2 output samples + unsigned short adc_buf[] // ADC_TUNER_BUF_SZ/2 input samples +) +{ int i, j, k; float x, y, z; int n, m, o; @@ -165,9 +169,9 @@ int main(void) { for(i=0; iODR |= (1 << 0); - //#define DUMMY_SIGNAL - #ifdef DUMMY_SIGNAL - - /* Fs/4 sine wave, right in the middle of the pass band ! */ - - for(i=0; iODR &= ~(1 << 2); } - diff --git a/codec2-dev/stm32/src/stm32f4_dacloduc.c b/codec2-dev/stm32/src/stm32f4_dacloduc.c new file mode 100644 index 00000000..a9b93f0a --- /dev/null +++ b/codec2-dev/stm32/src/stm32f4_dacloduc.c @@ -0,0 +1,276 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_dacloduc.c + AUTHOR......: David Rowe + DATE CREATED: Sep 2015 + + Experimental DAC driver module for STM32F4 that includes a low IF + Digital Up Converter (DUC). The Fs=96kHz signal is mixed up by a + (real) 24 kHz (Fs/4) local oscillator, then output by DAC1. + + DAC1 is connected to pin PA4. + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2015 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.h" +#include "codec2_fifo.h" +#include "stm32f4_dac.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_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 unsigned short dac1_buf[DAC_BUF_SZ]; + +static void tim6_config(void); +static void dac1_config(void); + +int dac_underflow; + +short signed_buf[DAC_BUF_SZ/2]; + +#define MAX_AMP 32767 + +void dac_open(int fifo_size) { + memset(dac1_buf, 32768, sizeof(short)*DAC_BUF_SZ); + + /* Create fifo */ + + dac1_fifo = fifo_create(fifo_size); + assert(dac1_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 configuration --------------------------*/ + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; + GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* Timer and DAC 1 Configuration --------------------------------------------*/ + + tim6_config(); + dac1_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); +} + +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 + = 84E6/TIM_ClockDivision (usually) + + ----------------------------------------------------------- */ + + /* Time base configuration */ + + TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); + TIM_TimeBaseStructure.TIM_Period = 875-1; /* 96 kHz */ + 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); +} + +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 + generation to be enable resulting in a low level tone on the + SM1000, that we thought was caused by analog issues like layout + or power supply biasing + */ + 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_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_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); +} + + +/******************************************************************************/ +/* 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) { + int i, j, sam; + short signed_buf[DAC_BUF_SZ/2]; + + 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, signed_buf, DAC_BUF_SZ/2) == -1) { + memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2); + dac_underflow++; + } + + for(i=0; iODR &= ~(1 << 1); +} + diff --git a/codec2-dev/stm32/src/usb_vcp_ut.c b/codec2-dev/stm32/src/usb_vcp_ut.c index 87ad9b8b..d060a73e 100644 --- a/codec2-dev/stm32/src/usb_vcp_ut.c +++ b/codec2-dev/stm32/src/usb_vcp_ut.c @@ -10,10 +10,30 @@ Remarkably, it compiled and ran first time, and even the LEDs blink as advertised, they just happen to match the LEDs on the SM1000! + However the speed was capped at about 130 kB/s. After a lot of + messing around I found suggestions in the comments from a similar + library here: - When I fired up Minicom, it echoed characters: + http://stm32f4-discovery.com/2014/08/library-24-virtual-com-port-vcp-stm32f4xx/ - $ sudo minicom -D /dev/ttyACM0 + The key was changing APP_RX_DATA_SIZE in usbd_conf.h to 10000. I + guess the previous size of 2048 was constraing the length of USB + packets, and the USB overhead meant slow throughput. I could + achieve a max of 450 kB/s with this change, about 1/3 of the + theoretical 1.5 MB/s max for USB FS (12 Mbit/s). + + I used this to test grabbing data from the STM32F4 Discovery: + $ sudo dd if=/dev/ttyACM0 of=/dev/null count=100 + 4+96 records in + 44+1 records out + 22615 bytes (23 kB) copied, 0.150884 s, 150 kB/s + + However I occasionally see: + $ sudo dd if=/dev/ttyACM0 of=/dev/null count=100 + dd: failed to open ‘/dev/ttyACM0’: Device or resource busy + + Googling found some suggestion that this is due to "modem manager", however I + removed MM and the problem still exists. \*---------------------------------------------------------------------------*/ @@ -22,42 +42,43 @@ #include "stm32f4_usb_vcp.h" #include "sm1000_leds_switches.h" -volatile uint32_t ticker, downTicker; +volatile uint32_t ticker, buf_ticker; + +#define N 640*6 + +short buf[N]; int main(void) { + int i; + for(i=0; i 500) { GPIOD->BSRRH = GPIO_Pin_13; } - else if (1000 == ticker) { + if (ticker > 1000) { ticker = 0; GPIOD->BSRRL = GPIO_Pin_13; } + /* Every 40ms send a buffer, simulates 16 bit samples at Fs=96kHz */ - /* If there's data on the virtual serial port: - * - Echo it back - * - Turn the green LED on for 10ms - */ - uint8_t theByte; - if (VCP_get_char(&theByte)) { - VCP_put_char(theByte); - - - GPIOD->BSRRL = GPIO_Pin_12; - downTicker = 10; - } - if (0 == downTicker) { - GPIOD->BSRRH = GPIO_Pin_12; + if (buf_ticker > 40) { + buf_ticker = 0; + led_pwr(1); + VCP_send_buffer((uint8_t*)buf, sizeof(buf)); + led_pwr(0); } + } return 0; @@ -70,9 +91,6 @@ int main(void) { void SysTick_Handler(void) { ticker++; - if (downTicker > 0) - { - downTicker--; - } + buf_ticker++; } -- 2.25.1