2020-12-06 01:08 AM
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
Solved! Go to Solution.
2020-12-06 11:39 PM
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
2020-12-06 07:52 AM
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?
2020-12-06 08:33 AM
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
2020-12-06 11:39 PM
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