2025-08-24 8:05 PM
Hello,
i have configured timer1 to trigger via CC1 an adc + dma.
For the DMA i have placed the TC irq routine and placed a gpio toggle to follow with a logic analyzer like shown below
void DMA2_Stream0_IRQHandler(void){
if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET)
{
GPIO_ResetBits(gpio_led_port,gpio_led2);
GPIO_SetBits(gpio_led_port,gpio_led2);
GPIO_ResetBits(gpio_led_port,gpio_led2);
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
}
}
And this is my nvic setup
SysTick_Config(SystemCoreClock / 1000);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
My problem is the DMA TC IRQ never triggeres, the timer1 cc1 output works...
The systick irq routine works
The thing is that i have tried to port the same code, to a stm32F407VG device, and there everything works as expected...
I remember that on the F410 devices i always have trouble running irq's, and i am not sure if this is related to the startup file.
Any advices on what to check?
2025-08-25 6:32 AM
NVIC_PriorityGroup_0 has 0 bits available for preemption, doesn't it?
Perhaps show the code where you use DMA. You could also look at the DMA registers after the DMA is started and when the TC interrupt fails to happen.
2025-08-25 6:52 AM
Hello @Bogdan
To facilitate debugging, begin with a basic ADC conversion using DMA. If this functions correctly, you can then incorporate the TIM trigger.
2025-08-25 7:18 AM
Read out and check/post content of TIM, ADC and DMA registers.
JW
2025-08-25 9:47 PM
Hello,
this is the adc dma function content
void adc1_dma_config(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
DMA_InitTypeDef DMA_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2| GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
DMA_Cmd(DMA2_Stream0, DISABLE);
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADCval[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // get from ADC1 periph and store to memory in ADCval[x]
DMA_InitStructure.DMA_BufferSize = TOTAL_ADC_CHANNELS_FOR_DMA; // 8 memory locations
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // enable to increment from ADCval[0] to... ADCval[2]
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // read ADC DR register continously and update the buffer values
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); // enable transfer complete interupt
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
// ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
//ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
// ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // multi channel
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; // trigger by timer1 CC1
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 3; //
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_CURRENT_W, 1, ADC_SampleTime_28Cycles);
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_CURRENT_V, 2, ADC_SampleTime_28Cycles );
ADC_RegularChannelConfig(ADC1, ADC_CHANNEL_CURRENT_U, 3, ADC_SampleTime_28Cycles );
ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
DMA_Cmd(DMA2_Stream0, ENABLE);
}
This is the timer setup
void timer1_config(void){
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN ;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_TIM1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1);
TIM_DeInit(TIM1);
TIM_InternalClockConfig(TIM1);
TIM_TimeBaseStructure.TIM_Prescaler = TIMER1_Prescaler_value;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
TIM_TimeBaseStructure.TIM_Period = TIMER1_AutoReload_value; //arr
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Channel 1 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = TIM1_DEFAULT_PWM_DUTYCYCLE;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;
TIM_BDTRInitStructure.TIM_DeadTime = 200;
TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
/* Select the Master Slave Mode */
TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);
TIM_SelectSlaveMode(TIM1, TIM_SlaveMode_Reset);//
TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_OC1Ref);
TIM_Cmd(TIM1, ENABLE);
/* Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
And this is the main code
int main(void){
SystemInit();
SysTick_Config(SystemCoreClock / 1000);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = SysTick_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RCC_ClocksTypeDef clocks;
RCC_GetClocksFreq(&clocks);
init_rcc_leds_clocks();
timer1_config();
adc1_dma_config();
while(1)
{
}
}
void DMA2_Stream0_IRQHandler(void){
if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) != RESET)
{
GPIO_ResetBits(gpio_led_port,gpio_led2);
GPIO_SetBits(gpio_led_port,gpio_led2);
GPIO_SetBits(gpio_led_port,gpio_led2);
GPIO_ResetBits(gpio_led_port,gpio_led2);
DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
}
}
void SysTick_Handler(void)
{
GPIO_SetBits(gpio_led_port,gpio_led1);
GPIO_ResetBits(gpio_led_port,gpio_led1);
}
i have done a little debuging last night and i noticed if i use optimization level to none -O0 the DMA IRQ does not run. The systick irq runs
But if set optimization level to -O3 the DMA TC IRQ runs
And i have another question, ADC EOC IRQ can run in the same time when using ADC DMA TC IRQ ?