cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G474 DMA Transfer Error and DAC underrun

Manu Abraham
Senior

Hi,

I am trying to write a waveform table to the DAC peripheral using DMA and the TIM6 peripheral.

TIM6 does appear to work as expected.

I can also see the DMA getting triggered by means of TIM6_TRGO.

But the DMA Transfer results in a Transfer Error, resulting in a DAC underrun. The latter expected due to the former error.

Something, I am missing in the DMA setup that causes TE IRQ to be raised, but somehow I am blind to the bug. Can someone lend another set of eyeballs, please ?

static void SystemClock_Config(void)
{
	LL_FLASH_SetLatency(LL_FLASH_LATENCY_7);
	LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
	LL_RCC_HSI_Enable();
	while (LL_RCC_HSI_IsReady() != 1) {}			/* Wait till HSI is ready */
 
	LL_RCC_HSI_SetCalibTrimming(64);
	LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, LL_RCC_PLLM_DIV_4, 75, LL_RCC_PLLR_DIV_2);
	LL_RCC_PLL_EnableDomain_SYS();
	LL_RCC_PLL_Enable();
	while (LL_RCC_PLL_IsReady() != 1) {}			/* Wait till PLL is ready */
 
	LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
	LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2);
 
	/* Wait till System clock is ready */
	while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {}
 
	/* ensure 1µs transition state at intermediate medium speed clock based on DWT */
	CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
	DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
	DWT->CYCCNT = 0;
	while (DWT->CYCCNT < 100);
 
	LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);		/* Set AHB prescaler*/
	LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
	LL_RCC_SetAPB2Prescaler(LL_RCC_APB1_DIV_1);
	LL_Init1msTick(150000000);
	LL_SetSystemCoreClock(150000000);
}
 
int main(void)
{
	LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);	/* SYSCFGEN */
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);	/* PWREN */
	NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
 
	SystemClock_Config();
 
	uart_init();
	led_init();
 
	printf("\n\t------------------\n");
	printf("\tSTM32G474 DAC Test\n");
	printf("\t------------------\n");
 
	dma_init();
	tim_init();
	dac_init();
 
	dac_enable();						/* Enable DAC */
 
	while (1) {}
}
 
static void dma_init(void)
{
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1);	/* DMAMUX clk enable */
	LL_DMA_SetPeriphRequest(DMA1,
				LL_DMA_CHANNEL_1,
				LL_DMAMUX_REQ_DAC1_CH1);	/* DMAMUX: DMA1_Ch1->DAC1_Ch1 */
 
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);	/* enable DMA1 clock */
 
	/* DAC1_CH1 Init */
	LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
	LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);
 
	LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
	LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
 
	LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
	LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
 
	LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);
 
	/* Set DMA transfer addresses of source and destination */
	LL_DMA_ConfigAddresses(DMA1,
			       LL_DMA_CHANNEL_1,
			       (uint32_t ) sin_tbl_12b_32samples,
			       LL_DAC_DMA_GetRegAddr(DAC1,
						     LL_DAC_CHANNEL_1,
						     LL_DAC_DMA_REG_DATA_12BITS_RIGHT_ALIGNED),
			       LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
 
	LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, TABLE_SIZE);
	NVIC_EnableIRQ(DMA1_Channel1_IRQn);			/* enable DMA1 CH1 IRQ */
 
	LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1);		/* Enable TX error DMARQ */
	LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);		/* Enable TC DMARQ */
 
	LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);		/* Enable DMA transfer */
}
 
static void tim_init(void)
{
	uint32_t clk, per, psc;
 
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);	/* enable TMR clock */
	NVIC_EnableIRQ(TIM6_DAC_IRQn);				/* enable TMR IRQ */
 
	if (LL_RCC_GetAPB1Prescaler() == LL_RCC_APB1_DIV_1)
		clk = __LL_RCC_CALC_PCLK1_FREQ(SystemCoreClock, LL_RCC_GetAPB1Prescaler());
	else
		clk = (__LL_RCC_CALC_PCLK1_FREQ(SystemCoreClock, LL_RCC_GetAPB1Prescaler()) * 2);
	
	/**
	 * Timer prescaler calculation
	 * Computation for timer 16 bits, additional + 1 to round the prescaler up
	 */
	psc = ((clk / (TMR_PSC_MAX * TMR_FREQ_MIN)) + 1);
	per = (clk / (psc * TMR_FREQ));				/* Timer reload calculation */
 
	LL_TIM_SetPrescaler(TIM6, (psc - 1));			/* set timer pre-scaler value */
	LL_TIM_SetAutoReload(TIM6, (per - 1));			/* set timer auto-reload value */
	LL_TIM_SetCounterMode(TIM6, LL_TIM_COUNTERMODE_UP);	/* set counter mode */
	LL_TIM_SetRepetitionCounter(TIM6, 0);			/* set the repetition counter */
 
	LL_TIM_DisableARRPreload(TIM6);
	LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_UPDATE);	/* DAC trigger output */
	LL_TIM_DisableMasterSlaveMode(TIM6);
 
	LL_TIM_EnableIT_UPDATE(TIM6);				/* enable Update IRQ */
	LL_TIM_EnableCounter(TIM6);				/* enable counter */
}
 
static void dac_init(void)
{
	LL_GPIO_InitTypeDef	gpio = {0};
 
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_DAC1);	/* enable DAC1 clock */
	LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);	/* enable GPIOA clock */
 
	NVIC_EnableIRQ(TIM6_DAC_IRQn);				/* enable DAC1 IRQ */
 
	gpio.Pin	= LL_GPIO_PIN_4;			/* PA.4 */
	gpio.Mode	= LL_GPIO_MODE_ANALOG;			/* PA.4 -> DAC1_OUT1 */
	gpio.Pull	= LL_GPIO_PULL_NO;
	LL_GPIO_Init(GPIOA, &gpio);
 
	LL_DAC_SetSignedFormat(DAC1,
			       LL_DAC_CHANNEL_1,
			       LL_DAC_SIGNED_FORMAT_DISABLE);	/* DAC channel OUT1 config */
 
	LL_DAC_SetWaveAutoGeneration(DAC1,			/* diasble waveform generator */
				     LL_DAC_CHANNEL_1,
				     LL_DAC_WAVE_AUTO_GENERATION_NONE);
 
	LL_DAC_SetTriggerSource(DAC1,
				LL_DAC_CHANNEL_1,
				LL_DAC_TRIG_EXT_TIM6_TRGO);	/* Select trigger source */
 
	LL_DAC_ConfigOutput(DAC1,				/* Set the DAC channel output */
			    LL_DAC_CHANNEL_1,
			    LL_DAC_OUTPUT_MODE_NORMAL,
			    LL_DAC_OUTPUT_BUFFER_ENABLE,
			    LL_DAC_OUTPUT_CONNECT_GPIO);
 
	LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1);		/* Enable DAC DMARQ */
//	LL_DAC_EnableIT_DMAUDR1(DAC1);				/* DAC Channel1 underrun IRQ */
}
 
void DMA1_Channel1_IRQHandler(void)
{
	if (LL_DMA_IsActiveFlag_TE1(DMA1)) {
		printf("- TE -\n");
		debug_dac();
		debug_dma();
		debug_dmach();
		LL_DMA_ClearFlag_TE1(DMA1);
	}
	if (LL_DMA_IsActiveFlag_TC1(DMA1)) {
		LL_DMA_ClearFlag_GI1(DMA1);
		LL_DMA_ClearFlag_TC1(DMA1);
		printf("- TC -\n");
	}
 
}
 
void TIM6_DAC_IRQHandler(void)
{
	if (LL_DAC_IsActiveFlag_DMAUDR1(DAC1)) {		/* Check for DAC Ch1 underrun IRQ */
//		printf("- UDR -\n");
		LL_DAC_ClearFlag_DMAUDR1(DAC1);			/* Clear flag DAC Ch1 underrun */
		LL_DAC_DisableIT_DMAUDR1(DAC1);
	}
 
	if (LL_TIM_IsActiveFlag_UPDATE(TIM6)) {
		LL_TIM_ClearFlag_UPDATE(TIM6);
		LL_GPIO_TogglePin(GPIOA, LL_GPIO_PIN_5);
	}
}
 

This results in the following output:

        ------------------
        STM32G474 DAC Test
        ------------------
- TE -
 
 --------------* DAC1 Debug *--------------
        Debug> DAC1->CR      :0x101f
        Debug> DAC1->SWTRIGR :0x00
        Debug> DAC1->DHR12R1 :0x00
        Debug> DAC1->DHR12L1 :0x00
        Debug> DAC1->DHR8R1  :0x00
        Debug> DAC1->DHR12R2 :0x00
        Debug> DAC1->DHR12L2 :0x00
        Debug> DAC1->DHR8R2  :0x00
        Debug> DAC1->DHR12RD :0x00
        Debug> DAC1->DHR12LD :0x00
        Debug> DAC1->DHR8RD  :0x00
        Debug> DAC1->DOR1          :0x00
        Debug> DAC1->DOR2          :0x00
        Debug> DAC1->SR      :0x2800
        Debug> DAC1->CCR     :0x1f001f
        Debug> DAC1->MCR     :0x00
        Debug> DAC1->SHSR1   :0x00
        Debug> DAC1->SHSR2   :0x00
        Debug> DAC1->SHHR    :0x10001
        Debug> DAC1->SHRR    :0x10001
        Debug> DAC1->STR1    :0x00
        Debug> DAC1->STR2    :0x00
        Debug> DAC1->STMODR  :0x00
 
 ------------------------------------------
 
 --------------* DMA1 Debug *--------------
        Debug> DMA1->ISR     :0x09
        Debug> DMA1->IFCR    :0x00
 
 ------------------------------------------
 
 --------------* DMA Chx Debug *--------------
        Debug> DMA_Ch1->CCR  :0x5ba
        Debug> DMA_Ch1->CNDTR:0x20
        Debug> DMA_Ch1->CPAR :0x50000808
        Debug> DMA_Ch1->CMAR :0x8001cbe
 
 ------------------------------------------
 

Any thoughts ?

Thanks,

Manu

This discussion is locked. Please start a new topic to ask your question.
1 ACCEPTED SOLUTION

Accepted Solutions

Figured out the problem.

DMA config should be done only after the DAC has been configured.

Little did I realize that the solution was available in the Cube G4 1.3 package.

Thanks,

Manu

View solution in original post

3 REPLIES 3
TDK
Super User

Nothing jumps out at me. What is the update rate on TIM6? What happens if you reduce it by an order of magnitude or more?

If you feel a post has answered your question, please click "Accept as Solution".

Measured a sq.wave on PA.5 toggling in the int. handler. It was running at about 14.3kHz, reduced it to 1.4kHz 140Hz, and to 14Hz.

Behaviour is unchanged. DMA transfer error. Ugh!

(Initially, I thought it was a peripheral address issue, but then that wasn't it. Wonder why TE .. )

The frequency calculation is incorrect though, but that shouldn't be a problem I guess ?

static const uint16_t sin_tbl_12b_32samples[] = {

   __SIGNAL_AMPLITUDE_SCALING(2048),

   __SIGNAL_AMPLITUDE_SCALING(2447),

   __SIGNAL_AMPLITUDE_SCALING(2831),

   __SIGNAL_AMPLITUDE_SCALING(3185),

   __SIGNAL_AMPLITUDE_SCALING(3495),

   __SIGNAL_AMPLITUDE_SCALING(3750),

   __SIGNAL_AMPLITUDE_SCALING(3939),

   __SIGNAL_AMPLITUDE_SCALING(4056),

   __SIGNAL_AMPLITUDE_SCALING(4095),

   __SIGNAL_AMPLITUDE_SCALING(4056),

   __SIGNAL_AMPLITUDE_SCALING(3939),

   __SIGNAL_AMPLITUDE_SCALING(3750),

   __SIGNAL_AMPLITUDE_SCALING(3495),

   __SIGNAL_AMPLITUDE_SCALING(3185),

   __SIGNAL_AMPLITUDE_SCALING(2831),

   __SIGNAL_AMPLITUDE_SCALING(2447),

   __SIGNAL_AMPLITUDE_SCALING(2048),

   __SIGNAL_AMPLITUDE_SCALING(1649),

   __SIGNAL_AMPLITUDE_SCALING(1265),

   __SIGNAL_AMPLITUDE_SCALING(911),

   __SIGNAL_AMPLITUDE_SCALING(601),

   __SIGNAL_AMPLITUDE_SCALING(346),

   __SIGNAL_AMPLITUDE_SCALING(157),

   __SIGNAL_AMPLITUDE_SCALING(40),

   __SIGNAL_AMPLITUDE_SCALING(0),

   __SIGNAL_AMPLITUDE_SCALING(40),

   __SIGNAL_AMPLITUDE_SCALING(157),

   __SIGNAL_AMPLITUDE_SCALING(346),

   __SIGNAL_AMPLITUDE_SCALING(601),

   __SIGNAL_AMPLITUDE_SCALING(911),

   __SIGNAL_AMPLITUDE_SCALING(1265),

   __SIGNAL_AMPLITUDE_SCALING(1649)

};

#define SIGNAL_FREQUENCY      ((uint32_t) 1)   /* Waveform frequency (Hz) */

#define TABLE_SIZE         ARRAY_SIZE(sin_tbl_12b_32samples)

#define TMR_FREQ         (SIGNAL_FREQUENCY * TABLE_SIZE)

#define TMR_FREQ_MIN         ((uint32_t) 1)

#define TMR_PSC_MAX         ((uint32_t) 0xffff - 1UL)      /* max 16bits */

Thanks,

Manu

Figured out the problem.

DMA config should be done only after the DAC has been configured.

Little did I realize that the solution was available in the Cube G4 1.3 package.

Thanks,

Manu