STM32H743 - DMA + DAC - How to program ?
dear ST,
I'm trying to program the STM32H743 to use DMA control of its DAC - my understanding is this involves use of a Timer also.
'Circular' mode would be relevant meaning the file being output (just a sine wave for now) is continually replayed. Memory to peripheral is I understand the correct mode for this application. And the Timer's 'update event' output is I think supposed to be used as the trigger output.
Initially I tried to implement this through MXCube without success. Next I found an example code kindly posted by someone although this was for the STM32G071, but still I thought it could be modified to suit the H743 as they seem to have similar peripherals. While the modified code runs it does not produce any output on the PA4 pin (due no doubt to my invalid modifications), but can you help me to understand the mistakes, please ?
I see the G071 datasheet makes no mention of 'BDMA', unlike the H743, but I'm unclear as to how the BDMA relates to the DMA in the H743. I think everything would be explained in the datasheet, but it's not a simple piece of information hence my request for your help in explaining, please.
Below is the code:
// Enable peripherals: GPIOA, DMA, DAC, TIM6.
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN; // enables GPIOA
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // enables DMA1 clock source, DMAmux1 clock enabled ?
RCC->APB1LENR |= RCC_APB1LENR_DAC12EN; // enables DAC1 (and DAC2) peripheral clock
RCC->APB1LENR |= RCC_APB1LENR_TIM6EN; // enables TIM6 clock
// Pin A4 output type: Analog.
GPIOA->MODER &= ~( 0x3 << ( 4 * 2 ) );
GPIOA->MODER |= ( 0x3 << ( 4 * 2 ) );
// DMA configuration (channel 1).
// CCR register:
// - Memory-to-peripheral
// - Circular mode enabled.
// - Increment memory ptr, don't increment periph ptr.
// - 16-bit data size for both source and destination.
// - High priority.
uint32_t dma_ccr_clr = ~( BDMA_CCR_MEM2MEM |
BDMA_CCR_PL |
BDMA_CCR_MSIZE |
BDMA_CCR_PSIZE |
BDMA_CCR_PINC |
BDMA_CCR_EN );
uint32_t dma_ccr_set = ( ( 0x2 << BDMA_CCR_PL_Pos ) |
( 0x1 << BDMA_CCR_MSIZE_Pos ) |
( 0x1 << BDMA_CCR_PSIZE_Pos ) |
BDMA_CCR_MINC |
BDMA_CCR_CIRC |
BDMA_CCR_DIR );
BDMA_Channel1->CCR &= dma_ccr_clr;
BDMA_Channel1->CCR |= dma_ccr_set;
// Select DAC Ch1 as DMA Ch1 request source in DMAMUX.
// Note: DMAMUX channel numbers are slightly confusing in
// the documentation. They aren't reliably 0- or 1-indexed.
DMAMUX1_Channel0->CCR &= ~( DMAMUX_CxCR_DMAREQ_ID );
DMAMUX1_Channel0->CCR |= ( 0x8 << DMAMUX_CxCR_DMAREQ_ID_Pos );
// Set DMA source and destination addresses.
// Source: Address of the sine wave buffer in memory.
BDMA_Channel1->CM1AR = ( uint32_t )&SINE_WAVE;
// Dest.: DAC1 Ch1 '12-bit right-aligned data' register.
BDMA_Channel1->CPAR = ( uint32_t )&( DAC1->DHR12R1 );
// Set DMA data transfer length (# of sine wave samples).
BDMA_Channel1->CNDTR = ( uint16_t )SINE_SAMPLES;
// Enable DMA1 Channels 1/2.
BDMA_Channel1->CCR |= ( BDMA_CCR_EN );
// TIM6 configuration.
// Set prescaler and autoreload for a 440Hz sine wave.
TIM6->PSC = ( 0x0000 );
TIM6->ARR = ( SystemCoreClock / ( 440 * SINE_SAMPLES ) );
// Enable trigger output on timer update events.
TIM6->CR2 &= ~( TIM_CR2_MMS );
TIM6->CR2 |= ( 0x2 << TIM_CR2_MMS_Pos );
// Start the timer.
TIM6->CR1 |= ( TIM_CR1_CEN );
// DAC configuration.
// Set trigger source to TIM6 TRGO.
DAC1->CR &= ~( DAC_CR_TSEL1 );
DAC1->CR |= ( 0x5 << DAC_CR_TSEL1_Pos );
// Set outputs to buffered GPIO 'normal mode'.
DAC1->MCR &= ~( DAC_MCR_MODE1 );
// Enable DAC DMA requests.
DAC1->CR |= ( DAC_CR_DMAEN1 );
// Enable DAC Channels.
DAC1->CR |= ( DAC_CR_EN1 );
// Enable DAC channel trigger.
DAC1->CR |= ( DAC_CR_TEN1 );