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

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
Guru

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