waveblender/dac.c
Daniele Lacamera 22ff79dcdf Initial import
2020-04-06 21:08:01 +02:00

174 rader
4,8 KiB
C

/*
* (c) danielinux 2020
* GPLv.2
*
* See LICENSE for details
*/
#include <unicore-mx/cm3/nvic.h>
#include <unicore-mx/stm32/dma.h>
#include <unicore-mx/stm32/dac.h>
#include <unicore-mx/stm32/gpio.h>
#include <unicore-mx/stm32/rcc.h>
#include <unicore-mx/stm32/timer.h>
#include "pot.h"
#define DAC_BUFSIZ 512
extern const unsigned char raw_au[];
const unsigned int raw_au_len;
static volatile int dac_written;
static int dac_transfer_size;
static int dac_chunk_size;
static uint8_t dac_outb[DAC_BUFSIZ];
static void dac_xmit(void)
{
uint32_t size = DAC_BUFSIZ;
if ((dac_transfer_size - dac_written ) < size)
size = dac_transfer_size - dac_written;
dac_chunk_size = size;
/* Start DMA transfer of waveform */
dac_trigger_enable(CHANNEL_1);
dac_set_trigger_source(DAC_CR_TSEL1_T2);
dac_dma_enable(CHANNEL_1);
dma_set_memory_address(DMA1, DMA_STREAM5, (uint32_t) (dac_outb + dac_written));
dma_set_number_of_data(DMA1, DMA_STREAM5, size);
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_write(const void *buf, unsigned int len)
{
if (dac_written < dac_transfer_size) {
if ((len + dac_transfer_size) > DAC_BUFSIZ)
return 0;
}
if (dac_written >= dac_transfer_size) {
dac_written = 0;
dac_transfer_size = 0;
}
memcpy(dac_outb + dac_transfer_size, buf, len);
dac_transfer_size += len;
dac_xmit();
return dac_written;
}
int dac_space(void)
{
if (dac_written >= dac_transfer_size) {
dac_written = 0;
dac_transfer_size = 0;
}
return DAC_BUFSIZ - dac_transfer_size;
}
/* IRQ Handler */
void dma1_stream5_isr(void)
{
if (dma_get_interrupt_flag(DMA1, DMA_STREAM5, DMA_TCIF)) {
if (dac_written < dac_transfer_size)
dac_written += dac_chunk_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);
if (dac_written >= dac_transfer_size) {
return;
} else {
dac_xmit();
}
}
}
/* 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_play(const uint8_t *buf, int len)
{
int i = 0;
int space;
while(i < len) {
space = dac_space();
if (space > 0) {
if (space > (len - i))
space = len - i;
dac_write(buf + i, space);
i += space;
}
}
}
int dac_init(void)
{
int i;
dac_hw_init(CHANNEL_1);
dac_dma_setup();
pot_set_master(200);
dac_play(raw_au, raw_au_len);
return 0;
}