I'm working on a project for a digital filter, see figure below. I have timer 3 triggering the ADC at 40kHz, the ADC should then make a sample and when its conversion is done it should trigger the DMA. The DMA should then move the converted value from the ADC peripheral memory to a memory address. Timer 3 works fine, however the DMA_IRQHandler code doesn't seem to work. Does anybody know if my configuration of the DMA or the ADC is wrong? My code is depicted below.
Many thanks!
void timer_init (void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 0;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 1050*2; // Sample frequentie, 40kHz
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
timerInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &timerInitStructure);
TIM_Cmd(TIM3, ENABLE);
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
}
void timer_interrupt_init (void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the timer global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init (&NVIC_InitStructure);
//NVIC_SetPriority(TIM3_IRQn, 2);
}
void timer_start (void)
{
TIM_Cmd (TIM3, ENABLE);
}
void timer_stop (void)
{
TIM_Cmd (TIM3, DISABLE);
}
void timer_interrupt_enable (void)
{
/*
* It is important to clear any pending interrupt flags since the timer
* has been free-running since we last used it and that will generate
* interrupts on overflow even though the associated interrupt event has
* not been enabled.
*/
TIM_ClearITPendingBit (TIM3, TIM_IT_Update);
/* put the counter into a known state */
TIM_SetCounter (TIM3, 0);
TIM_ITConfig (TIM3, TIM_IT_Update, ENABLE);
}
void timer_interrupt_disable (void)
{
TIM_ITConfig (TIM3, TIM_IT_Update, DISABLE);
}
void TIM3_IRQHandler (void)
{
if (TIM_GetITStatus (TIM3, TIM_IT_Update) != RESET)
{
//GPIO_ToggleBits(GPIOD, GREEN_PIN); // For checking the timer frequency with a scope
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}
}
void adc_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); // Enable the clock for the ADC peripheral
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);// Enable the clock for the GPIO peripheral
// Configure GPIO PC1 to analog mode
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Configure the common adc parameters
ADC_CommonInitTypeDef ADC_CommonInitStruct;
ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStruct);
// Configure the specific adc parameters
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; // ADC gets triggered by timer 3
ADC_InitStruct.ADC_NbrOfConversion = 1; // single conversion
ADC_Init(ADC2, &ADC_InitStruct);
ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);
ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
ADC_DMACmd(ADC2, ENABLE);
ADC_Cmd(ADC2, ENABLE);
}
void DMA_Initialize(void)
{
RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
DMA_InitTypeDef DMA_InitStructure;
/* Initialise DMA */
DMA_StructInit(&DMA_InitStructure);
DMA_DeInit(DMA2_Stream3); //Set DMA registers to default values
/* config of DMAC */
DMA_InitStructure.DMA_Channel = DMA_Channel_1; /* This channel is linked to ADC2*/
DMA_InitStructure.DMA_BufferSize = 1; /* Size in words of the buffer where the adc sample value gets stored */
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; /* direction */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; /* no FIFO */
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* here you van select normal mode or circular buffer */
DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* here you can select the priority of the dma stream. */
/* config of memory */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_value; /* target addr */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA_MemoryDataSize_Word /* 16 bit */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_Init(DMA2_Stream3, &DMA_InitStructure); /* See Table 20 for mapping */
DMA_Cmd(DMA2_Stream3, ENABLE);
DMA_ITConfig(DMA2_Stream3,DMA_IT_TC, ENABLE);
}
void DMA2_Stream3_IRQHandler()
{
if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TCIF3) != RESET)
{
DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);
GPIO_ToggleBits(GPIOD, RED_PIN);
}
}