#include "set_wave_f407.h" #include "stm32f4xx.h" static void stop(void *context) { unsigned limit=100000; (void)context; RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN|RCC_AHB1ENR_DMA1EN; RCC->APB1ENR|=RCC_APB1ENR_DACEN|RCC_APB1ENR_TIM6EN; (void)RCC->APB1ENR; TIM6->CR1=0; DAC->CR&=~(DAC_CR_DMAEN1|DAC_CR_TEN1); DMA1_Stream5->CR&=~DMA_SxCR_EN; while((DMA1_Stream5->CR&DMA_SxCR_EN)&&--limit) {} /* Leave other DAC channel untouched. Channel 1 outputs zero on stop. */ DAC->DHR12R1=0; DMA1->HIFCR=0xF40u; DAC->SR=DAC_SR_DMAUDR1; } static int start(void *context,const uint16_t *samples,size_t count,uint32_t rate) { set_wave_f407 *c=(set_wave_f407 *)context; uint32_t ticks,psc,arr; uintptr_t address=(uintptr_t)samples; if(!c||!rate||rate>SET_WAVE_MAX_RATE||count<2||count>SET_WAVE_MAX||c->timer_hz%rate ||address<0x20000000u||address+count*2>0x20020000u) return 1; ticks=c->timer_hz/rate; for(psc=1;psc<=65536;++psc) if(ticks%psc==0&&ticks/psc<=65536) break; if(psc>65536||ticksCR&DMA_SxCR_EN) return 1; GPIOA->MODER|=3u<<8; GPIOA->PUPDR&=~(3u<<8); TIM6->PSC=psc-1;TIM6->ARR=arr-1;TIM6->CNT=0; TIM6->CR2=0;TIM6->EGR=TIM_EGR_UG;TIM6->SR=0; TIM6->CR2=TIM_CR2_MMS_1; /* update -> TRGO */ DMA1_Stream5->PAR=(uint32_t)&DAC->DHR12R1; DMA1_Stream5->M0AR=(uint32_t)samples;DMA1_Stream5->NDTR=(uint32_t)count; DMA1_Stream5->FCR=0; DMA1_Stream5->CR=(7u<<25)|DMA_SxCR_DIR_0|DMA_SxCR_MINC|DMA_SxCR_CIRC |DMA_SxCR_PSIZE_0|DMA_SxCR_MSIZE_0|DMA_SxCR_PL_1; /* Prime the previous period's last sample; DMA supplies the next value * after each trigger. Cyclic order is last,0,1,... with one priming tick. */ DAC->CR&=~0xFFFFu; DAC->DHR12R1=samples[count-1]; DAC->CR|=DAC_CR_EN1|DAC_CR_TEN1|DAC_CR_DMAEN1; /* TSEL1=0: TIM6 */ DMA1_Stream5->CR|=DMA_SxCR_EN; TIM6->CR1=TIM_CR1_CEN; return 0; } set_wave_port set_wave_f407_port(set_wave_f407 *context) { set_wave_port port={context,start,stop};return port; } int set_wave_f407_fault(void) { return (DMA1->HISR&(DMA_HISR_TEIF5|DMA_HISR_DMEIF5|DMA_HISR_FEIF5)) ||(DAC->SR&DAC_SR_DMAUDR1); }