/* * (c) danielinux 2020 * GPLv.2 * * See LICENSE for details */ #include #include #include #include #include #include #include #include "pot.h" #include "timer.h" #include "system.h" #define DAC_BUFSIZ (512) #define DAC_MEMSIZ (4 * DAC_BUFSIZ) extern const unsigned char raw_au[]; extern volatile uint32_t jiffies; const unsigned int raw_au_len; static int dac_transfer_size; static uint8_t dac_memory[DAC_MEMSIZ]; static volatile uint32_t dac_written; static volatile int direct = 0; static volatile int dac_busy = 0; int dac_is_busy(void) { return dac_busy; } static void dac_xmit(void) { uint32_t size = DAC_BUFSIZ; if ((dac_transfer_size == 0) || (dac_written >= dac_transfer_size)) { dac_written = 0; dac_transfer_size = 0; memset(dac_memory, 0, DAC_MEMSIZ); } else { if ((dac_transfer_size - dac_written) < size) size = dac_transfer_size - dac_written; if (size == 0) { dac_transfer_size = 0; dac_written = 0; memset(dac_memory, 0, DAC_MEMSIZ); } } if (dac_transfer_size == 0) { dma_disable_stream(DMA1, DMA_STREAM5); dac_trigger_disable(CHANNEL_1); dac_dma_disable(CHANNEL_1); return; } dma_set_number_of_data(DMA1, DMA_STREAM5, size); dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t)(dac_memory + dac_written)); direct = 0; /* Start DMA transfer of waveform */ dac_trigger_enable(CHANNEL_1); dac_set_trigger_source(DAC_CR_TSEL1_T2); dac_dma_enable(CHANNEL_1); dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5); dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_7); dma_enable_stream(DMA1, DMA_STREAM5); } int dac_space(void) { return DAC_MEMSIZ - dac_transfer_size; } /* IRQ Handler */ void dma1_stream5_isr(void) { if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_TCIF)) { dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF); dma_disable_stream(DMA1, DMA_STREAM5); dac_trigger_disable(CHANNEL_1); dac_dma_disable(CHANNEL_1); dac_busy = 0; if (!direct) { if (dac_written < dac_transfer_size) { dac_written += DAC_BUFSIZ; } else { dac_written = 0; dac_transfer_size = 0; return; } dac_xmit(); } } } void dac_stop(void) { dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF); dma_disable_stream(DMA1, DMA_STREAM5); dac_trigger_disable(CHANNEL_1); dac_dma_disable(CHANNEL_1); dac_busy = 0; } void dac_play_direct(uint8_t *mem, uint32_t size) { dma_clear_interrupt_flags(DMA1, DMA_STREAM5, DMA_TCIF); dma_disable_stream(DMA1, DMA_STREAM5); dac_trigger_disable(CHANNEL_1); dac_dma_disable(CHANNEL_1); dma_set_number_of_data(DMA1, DMA_STREAM5, size); dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t)mem); direct = 1; dac_busy = 1; /* Start DMA transfer of waveform */ dac_trigger_enable(CHANNEL_1); dac_set_trigger_source(DAC_CR_TSEL1_T2); dac_dma_enable(CHANNEL_1); dma_enable_transfer_complete_interrupt(DMA1, DMA_STREAM5); dma_channel_select(DMA1, DMA_STREAM5, DMA_SxCR_CHSEL_7); dma_enable_stream(DMA1, DMA_STREAM5); } /* Initialization functions */ //#define PERIOD (5200) #define PERIOD 8800 static void timer_setup(void) { /* Enable TIM2 clock. */ rcc_periph_clock_enable(RCC_TIM2); timer_reset(TIM2); /* Timer global mode: - No divider, Alignment edge, Direction up */ timer_set_mode(TIM2, TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); timer_continuous_mode(TIM2); timer_set_period(TIM2, PERIOD); timer_disable_oc_output(TIM2, TIM_OC2 | TIM_OC3 | TIM_OC4); timer_enable_oc_output(TIM2, TIM_OC1); timer_disable_oc_clear(TIM2, TIM_OC1); timer_disable_oc_preload(TIM2, TIM_OC1); timer_set_oc_slow_mode(TIM2, TIM_OC1); timer_set_oc_mode(TIM2, TIM_OC1, TIM_OCM_TOGGLE); timer_set_oc_value(TIM2, TIM_OC1, 500); timer_disable_preload(TIM2); /* Set the timer trigger output (for the DAC) to the channel 1 output * compare */ timer_set_master_mode(TIM2, TIM_CR2_MMS_COMPARE_OC1REF); timer_enable_counter(TIM2); } static void dac_dma_setup(void) { /* DAC channel 1 uses DMA controller 1 Stream 5 Channel 7. */ /* Enable DMA1 clock and IRQ */ rcc_periph_clock_enable(RCC_DMA1); nvic_set_priority(NVIC_DMA1_STREAM5_IRQ, 1); nvic_enable_irq(NVIC_DMA1_STREAM5_IRQ); dma_stream_reset(DMA1, DMA_STREAM5); dma_set_priority(DMA1, DMA_STREAM5, DMA_SxCR_PL_LOW); dma_set_memory_size(DMA1, DMA_STREAM5, DMA_SxCR_MSIZE_8BIT); dma_set_peripheral_size(DMA1, DMA_STREAM5, DMA_SxCR_PSIZE_8BIT); dma_enable_memory_increment_mode(DMA1, DMA_STREAM5); dma_enable_circular_mode(DMA1, DMA_STREAM5); dma_set_transfer_mode(DMA1, DMA_STREAM5, DMA_SxCR_DIR_MEM_TO_PERIPHERAL); /* The register to target is the DAC1 8-bit right justified data register */ dma_set_peripheral_address(DMA1, DMA_STREAM5, (uint32_t) &DAC_DHR8R1); } static void dac_hw_init(data_channel c) { /* Set DAC GPIO pin to analog mode */ rcc_periph_clock_enable(RCC_GPIOC); gpio_mode_setup(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO4); timer_setup(); /* Set up DAC */ rcc_periph_clock_enable(RCC_DAC); dac_enable(c); } void dac_reset(void) { dac_written = 0; dac_transfer_size = 0; } void dac_play(const uint8_t *buf, int len) { int i = 0; int space; int w = 0; dac_written = 0; dac_transfer_size = 0; while (len > 0) { space = DAC_MEMSIZ; if (space > len) { space = len; } if (dac_space() == 0) { WFI(); continue; } memcpy(dac_memory, buf + w, space); dac_transfer_size = space; dac_xmit(); len -= space; w += space; } } extern unsigned char drumkit_0_au[]; extern unsigned char drumkit_1_au[]; extern unsigned char drumkit_2_au[]; extern unsigned int drumkit_0_au_len; extern unsigned int drumkit_1_au_len; extern unsigned int drumkit_2_au_len; int dac_init(void) { int i; uint32_t now; dac_hw_init(CHANNEL_1); dac_dma_setup(); pot_set_master(100); // dac_play(drumkit_0_au, drumkit_0_au_len); // dac_play(raw_au, raw_au_len); dac_play_direct(drumkit_2_au, drumkit_2_au_len); while(dac_is_busy()) WFI(); return 0; }