54 lines
2.2 KiB
C
54 lines
2.2 KiB
C
#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||ticks<psc) return 1;
|
|
arr=ticks/psc;
|
|
stop(context);
|
|
if(DMA1_Stream5->CR&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);
|
|
}
|