merged Stuarts latest, compiles OK, haven't tested
authordrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 6 Nov 2015 01:15:40 +0000 (01:15 +0000)
committerdrowe67 <drowe67@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 6 Nov 2015 01:15:40 +0000 (01:15 +0000)
git-svn-id: https://svn.code.sf.net/p/freetel/code@2481 01035d8c-6547-0410-b346-abe4f91aad63

13 files changed:
codec2-dev/stm32/Makefile
codec2-dev/stm32/inc/stm32f4_adc_tuner.h
codec2-dev/stm32/inc/stm32f4_usb_vcp.h
codec2-dev/stm32/src/adc_sfdr_ut.c
codec2-dev/stm32/src/codec2_profile.c
codec2-dev/stm32/src/dac_ut.c
codec2-dev/stm32/src/fast_dac_ut.c
codec2-dev/stm32/src/gdb_stdio.c
codec2-dev/stm32/src/iir_tuner.c
codec2-dev/stm32/src/stm32f4_adc_tuner.c
codec2-dev/stm32/src/stm32f4_dac.c
codec2-dev/stm32/src/stm32f4_dacloduc.c [new file with mode: 0644]
codec2-dev/stm32/src/usb_vcp_ut.c

index a2a0248d189a3f9636e65dd1cdbdf2c0d2c208ef..537fccd0e960c1ae6ec4c4d99fdebd779382b0e4 100644 (file)
@@ -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
index 6c7c755969b78dce06d953b839db48abb5d63b72..a258b9d895f433f1b73fd1154fae591d0b2e4e96 100644 (file)
@@ -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)
 
index 384f3f0b9fdb0af2a8ecd660e9e8071d288575a3..d742ebc160659008935f201bf1af556ac824700d 100644 (file)
@@ -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
index 21853b46fe895478213f746d119b14ac8ad04b1a..952ecef073d607febcb0ff1571d5cd1062d5ffb4 100644 (file)
@@ -88,3 +88,4 @@ int main(void) {
     printf("Finished!\n");
 }
 
+>>>>>>> .r2480\r
index 73ca7247dc52256c732c6fde1685c8e1ab7c04ac..5537bad5efed5e9c8b89d9a51f067b31dfb91966 100644 (file)
@@ -179,4 +179,3 @@ int main(int argc, char *argv[]) {
 
     return 0;
 }
-
index 872ecf681a2b2d841552d8a4cf5e7da32e3314d8..f38d72de9cea55330bb8c6b36b370743b3c7a779 100644 (file)
@@ -57,3 +57,4 @@ int main(void) {
 
 }
 
+>>>>>>> .r2480\r
index 9712c441dd19338dc39b24f9f64bc87c4bed4e37..e9b50f8f6409a2e76e057ab0a7494a668a5ec550 100644 (file)
@@ -112,4 +112,3 @@ int main(void) {
     }
 
 }
-
index ef7e12a103cb6b65a0fd32830b73bbe53a060b7c..46245e4cc28ae06075152a68a08b7266d9152e18 100644 (file)
@@ -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;
index c92d352fdddfb05e8afd61f873530f27d7cee23e..2baae590f756678c033191352afec1489e32ab39 100644 (file)
@@ -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; i<NIN; i++)
         s[i] = 32767;
-    synth_line(s, f2, 0.1, NIN);
-    synth_line(s, f3, 0.05, NIN);
-    synth_line(s, f4, 0.1, NIN);
+    synth_line(s, f1, 1, NIN);
+    //synth_line(s, f3, 0.1, NIN);
+    //synth_line(s, f4, 0.2, NIN);
     for(i=0, j=0; i<NIN; i+=ADC_TUNER_BUF_SZ/2, j+=ADC_TUNER_N/2) {
         iir_tuner(&dec_50[j], &s[i]);
     }
index 30caf8034c5a4efa9f9b4e7e6709b0a6b71f9e44..f3de154e99165a921253fdccdf95cd01b3eef068 100644 (file)
@@ -42,7 +42,7 @@
 #include "iir_tuner.h"
 
 struct FIFO *adc1_fifo;
-unsigned short adc_buf[ADC_TUNER_BUF_SZ];
+unsigned short adc_buf[ADC_TUNER_BUF_SZ], *padc_buf;
 int adc_overflow1;
 int half,full;
 static short tuner_en = 1;
@@ -56,6 +56,10 @@ void adc_configure();
 
 static void tim2_config(void);
 
+//#define DUMMY_SIGNAL
+#ifdef DUMMY_SIGNAL
+unsigned short sine[ADC_TUNER_BUF_SZ];
+#endif
 
 void adc_open(int fifo_sz) {
     adc1_fifo = fifo_create(fifo_sz);
@@ -201,6 +205,23 @@ void adc_configure() {
 
     ADC_Cmd(ADC1,ENABLE);
     ADC_SoftwareStartConv(ADC1);
+
+    padc_buf = adc_buf;
+
+    #ifdef DUMMY_SIGNAL
+    int i;
+
+    /* Fs/4 sine wave, right in the middle of the pass band ! */
+
+    for(i=0; i<ADC_TUNER_BUF_SZ; i++)
+        sine[i] = 32767;
+    for(i=1; i<ADC_TUNER_BUF_SZ; i+=4)
+        sine[i] += 32767/4;
+    for(i=3; i<ADC_TUNER_BUF_SZ; i+=4)
+        sine[i] -= 32767/4;
+    padc_buf = sine;
+    #endif
+
 }
 
 
@@ -213,42 +234,28 @@ void adc_configure() {
 
 void DMA2_Stream0_IRQHandler(void) {
     float dec_buf[ADC_TUNER_N/2];
-    int i;
 
     /* PE0 is asserted high for the duration of this ISR */
 
     GPIOE->ODR |= (1 << 0);
 
-    //#define DUMMY_SIGNAL
-    #ifdef DUMMY_SIGNAL
-
-    /* Fs/4 sine wave, right in the middle of the pass band ! */
-
-    for(i=0; i<ADC_TUNER_BUF_SZ; i++)
-        adc_buf[i] = 32767;
-    for(i=1; i<ADC_TUNER_BUF_SZ; i+=4)
-        adc_buf[i] += 32767;
-    for(i=3; i<ADC_TUNER_BUF_SZ; i+=4)
-        adc_buf[i] -= 32767;
-
-    #endif
-
     /* Half transfer interrupt */
 
     if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0) != RESET) {
         half++;
 
         if (tuner_en) {
-            iir_tuner(dec_buf, adc_buf);
+            iir_tuner(dec_buf, padc_buf);
 
-            /* write first half to fifo */
+            /* write first half to fifo.  Note we are writing ADC_TUNER_N/2 floats,
+               which is equivalent to ADC_TUNER_N shorts.  */
 
-            if (fifo_write(adc1_fifo, (short*)dec_buf, ADC_TUNER_N) == -1) {
+           if (fifo_write(adc1_fifo, (short*)dec_buf, ADC_TUNER_N) == -1) {
                 adc_overflow1++;
             }
         }
-        else
-            fifo_write(adc1_fifo, (short*)adc_buf, ADC_TUNER_BUF_SZ/2);
+        else // note: we dump signed shorts when tuner off
+            fifo_write(adc1_fifo, (short*)padc_buf, ADC_TUNER_BUF_SZ/2); 
 
         /* Clear DMA Stream Transfer Complete interrupt pending bit */
 
@@ -261,7 +268,7 @@ void DMA2_Stream0_IRQHandler(void) {
         full++;
 
         if (tuner_en) {
-            iir_tuner(dec_buf, &adc_buf[ADC_TUNER_BUF_SZ/2]);
+            iir_tuner(dec_buf, &padc_buf[ADC_TUNER_BUF_SZ/2]);
 
             /* write second half to fifo */
 
@@ -270,7 +277,7 @@ void DMA2_Stream0_IRQHandler(void) {
             }
         }
         else
-            fifo_write(adc1_fifo, (short*)&adc_buf[ADC_TUNER_BUF_SZ/2], ADC_TUNER_BUF_SZ/2);
+            fifo_write(adc1_fifo, (short*)&padc_buf[ADC_TUNER_BUF_SZ/2], ADC_TUNER_BUF_SZ/2);
 
         /* Clear DMA Stream Transfer Complete interrupt pending bit */
 
index f78004da475e4262f73301e78354d4b4084281e0..fa0831e1be429f9366aa928637e0945547e01da4 100644 (file)
@@ -403,4 +403,3 @@ void DMA1_Stream6_IRQHandler(void) {
 
     GPIOE->ODR &= ~(1 << 2);
 }
-
diff --git a/codec2-dev/stm32/src/stm32f4_dacloduc.c b/codec2-dev/stm32/src/stm32f4_dacloduc.c
new file mode 100644 (file)
index 0000000..a9b93f0
--- /dev/null
@@ -0,0 +1,276 @@
+/*---------------------------------------------------------------------------*\\r
+\r
+  FILE........: stm32f4_dacloduc.c\r
+  AUTHOR......: David Rowe\r
+  DATE CREATED: Sep 2015\r
+\r
+  Experimental DAC driver module for STM32F4 that includes a low IF\r
+  Digital Up Converter (DUC).  The Fs=96kHz signal is mixed up by a\r
+  (real) 24 kHz (Fs/4) local oscillator, then output by DAC1.\r
+\r
+  DAC1 is connected to pin PA4.\r
+\r
+\*---------------------------------------------------------------------------*/\r
+\r
+/*\r
+  Copyright (C) 2015 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 <assert.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <math.h>\r
+#include "stm32f4xx.h"\r
+#include "codec2_fifo.h"\r
+#include "stm32f4_dac.h"\r
+#include "debugblinky.h"\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
+#define DAC_DHR12R1_ADDRESS    0x40007408\r
+\r
+#define DAC_MAX      4096            /* maximum amplitude */\r
+\r
+/* y=mx+c mapping of samples16 bit shorts to DAC samples.  Table: 74\r
+   of data sheet indicates With DAC buffer on, DAC range is limited to\r
+   0x0E0 to 0xF1C at VREF+ = 3.6 V, we have Vref=3.3V which is close.\r
+ */\r
+\r
+#define M ((3868.0-224.0)/65536.0)\r
+#define C 2047.0\r
+\r
+static struct FIFO *dac1_fifo;\r
+\r
+static unsigned short dac1_buf[DAC_BUF_SZ];\r
+\r
+static void tim6_config(void);\r
+static void dac1_config(void);\r
+\r
+int dac_underflow;\r
+\r
+short signed_buf[DAC_BUF_SZ/2];\r
+\r
+#define MAX_AMP 32767\r
+\r
+void dac_open(int fifo_size) {\r
+    memset(dac1_buf, 32768, sizeof(short)*DAC_BUF_SZ);\r
+\r
+    /* Create fifo */\r
+\r
+    dac1_fifo = fifo_create(fifo_size);\r
+    assert(dac1_fifo != NULL);\r
+\r
+    /* Turn on the clocks we need -----------------------------------------------*/\r
+\r
+    /* DMA1 clock enable */\r
+    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);\r
+    /* GPIOA clock enable (to be used with DAC) */\r
+    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);                         \r
+    /* DAC Periph clock enable */\r
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);\r
+\r
+    /* GPIO Pin configuration DAC1->PA.4 configuration --------------------------*/\r
+\r
+    GPIO_InitTypeDef GPIO_InitStructure;\r
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;\r
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;\r
+    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;\r
+    GPIO_Init(GPIOA, &GPIO_InitStructure);\r
+\r
+    /* Timer and DAC 1 Configuration --------------------------------------------*/\r
+\r
+    tim6_config();  \r
+    dac1_config();\r
+\r
+    init_debug_blinky();\r
+}\r
+\r
+/* Call these puppies to send samples to the DACs.  For your\r
+   convenience they accept signed 16 bit samples. */\r
+\r
+int dac1_write(short buf[], int n) {   \r
+    return fifo_write(dac1_fifo, buf, n);\r
+}\r
+\r
+static void tim6_config(void)\r
+{\r
+  TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;\r
+\r
+  /* TIM6 Periph clock enable */\r
+  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);\r
+  \r
+  /* --------------------------------------------------------\r
+  \r
+  TIM6 input clock (TIM6CLK) is set to 2 * APB1 clock (PCLK1), since\r
+  APB1 prescaler is different from 1 (see system_stm32f4xx.c and Fig\r
+  13 clock tree figure in DM0031020.pdf).\r
+\r
+     Sample rate Fs = 2*PCLK1/TIM_ClockDivision \r
+                    = (HCLK/2)/TIM_ClockDivision\r
+                    = 84E6/TIM_ClockDivision (usually)\r
+\r
+  ----------------------------------------------------------- */\r
+\r
+  /* Time base configuration */\r
+\r
+  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); \r
+  TIM_TimeBaseStructure.TIM_Period = 875-1;         /* 96 kHz */\r
+  TIM_TimeBaseStructure.TIM_Prescaler = 0;       \r
+  TIM_TimeBaseStructure.TIM_ClockDivision = 0;    \r
+  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  \r
+  TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);\r
+\r
+  /* TIM6 TRGO selection */\r
+\r
+  TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);\r
+  \r
+  /* TIM6 enable counter */\r
+\r
+  TIM_Cmd(TIM6, ENABLE);\r
+}\r
+\r
+static void dac1_config(void)\r
+{\r
+  DAC_InitTypeDef  DAC_InitStructure;\r
+  DMA_InitTypeDef  DMA_InitStructure;\r
+  NVIC_InitTypeDef NVIC_InitStructure;\r
+  \r
+  /* DAC channel 1 Configuration */\r
+\r
+  /* \r
+     This line fixed a bug that cost me 5 days, bad wave amplitude\r
+     value, and some STM32F4 periph library bugs caused triangle wave\r
+     generation to be enable resulting in a low level tone on the\r
+     SM1000, that we thought was caused by analog issues like layout\r
+     or power supply biasing\r
+  */\r
+  DAC_StructInit(&DAC_InitStructure); \r
+\r
+  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; \r
+  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;\r
+  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable;\r
+  DAC_Init(DAC_Channel_1, &DAC_InitStructure);\r
+\r
+  /* DMA1_Stream5 channel7 configuration **************************************/\r
+  /* Table 35 page 219 of the monster data sheet */\r
+\r
+  DMA_DeInit(DMA1_Stream5);\r
+  DMA_InitStructure.DMA_Channel = DMA_Channel_7;  \r
+  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R1_ADDRESS;\r
+  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dac1_buf;\r
+  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;\r
+  DMA_InitStructure.DMA_BufferSize = DAC_BUF_SZ;\r
+  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;\r
+  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;\r
+  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;\r
+  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;\r
+  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;\r
+  DMA_InitStructure.DMA_Priority = DMA_Priority_High;\r
+  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         \r
+  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;\r
+  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;\r
+  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;\r
+  DMA_Init(DMA1_Stream5, &DMA_InitStructure);\r
+\r
+  /* Enable DMA Half & Complete interrupts */\r
+\r
+  DMA_ITConfig(DMA1_Stream5, DMA_IT_TC | DMA_IT_HT, ENABLE);\r
+\r
+  /* Enable the DMA Stream IRQ Channel */\r
+\r
+  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn;\r
+  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;\r
+  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;\r
+  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;\r
+  NVIC_Init(&NVIC_InitStructure);     \r
+\r
+  /* Enable DMA1_Stream5 */\r
+\r
+  DMA_Cmd(DMA1_Stream5, ENABLE);\r
+\r
+  /* Enable DAC Channel 1 */\r
+\r
+  DAC_Cmd(DAC_Channel_1, ENABLE);\r
+\r
+  /* Enable DMA for DAC Channel 1 */\r
+\r
+  DAC_DMACmd(DAC_Channel_1, ENABLE);\r
+}\r
+\r
+\r
+/******************************************************************************/\r
+/*                 STM32F4xx Peripherals Interrupt Handlers                   */\r
+/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */\r
+/*  available peripheral interrupt handler's name please refer to the startup */\r
+/*  file (startup_stm32f40xx.s/startup_stm32f427x.s).                         */\r
+/******************************************************************************/\r
+\r
+/*\r
+  This function handles DMA1 Stream 5 interrupt request for DAC1.\r
+*/\r
+\r
+void DMA1_Stream5_IRQHandler(void) {\r
+    int i, j, sam;\r
+    short signed_buf[DAC_BUF_SZ/2];\r
+\r
+    GPIOE->ODR |= (1 << 1);\r
+\r
+    /* Transfer half empty interrupt - refill first half */\r
+\r
+    if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_HTIF5) != RESET) {\r
+\r
+        /* fill first half from fifo */\r
+\r
+        if (fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
+            memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
+            dac_underflow++;\r
+        }\r
+\r
+        for(i=0; i<DAC_BUF_SZ/2; i++) {\r
+            sam = (int)(M*(float)signed_buf[i] + C);\r
+            dac1_buf[i] = (unsigned short)sam;\r
+        }\r
+\r
+        /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
+\r
+        DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_HTIF5);  \r
+    }\r
+\r
+    /* Transfer complete interrupt - refill 2nd half */\r
+\r
+    if(DMA_GetITStatus(DMA1_Stream5, DMA_IT_TCIF5) != RESET) {\r
+\r
+        /* fill second half from fifo */\r
+\r
+        if (fifo_read(dac1_fifo, signed_buf, DAC_BUF_SZ/2) == -1) {\r
+            memset(signed_buf, 0, sizeof(short)*DAC_BUF_SZ/2);\r
+            dac_underflow++;\r
+        }\r
+\r
+        for(i=0, j=DAC_BUF_SZ/2; i<DAC_BUF_SZ/2; i++, j++) {\r
+            sam = (int)(M*(float)signed_buf[i] + C);\r
+            dac1_buf[j] = (unsigned short)sam;\r
+        }\r
+\r
+        /* Clear DMA Stream Transfer Complete interrupt pending bit */\r
+\r
+        DMA_ClearITPendingBit(DMA1_Stream5, DMA_IT_TCIF5);  \r
+    }\r
+\r
+    GPIOE->ODR &= ~(1 << 1);\r
+}\r
+\r
index 87ad9b8bbe48c32336678ad9859c4d2954334ceb..d060a73e3b7677de04db9654194763034eeb2843 100644 (file)
 
   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.
 
 \*---------------------------------------------------------------------------*/
 
 #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<N; i++)
+        buf[i] = 0;
+    
     sm1000_leds_switches_init();
     usb_vcp_init();
     SysTick_Config(SystemCoreClock/1000);
 
     while (1) {
 
-        /* Blink the orange LED at 1Hz */
+        /* Blink the discovery red LED at 1Hz */
 
-        if (500 == ticker) {
+        if (ticker > 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++;
 }