2014-03-26 08:54 AM
I have looked over the following code many times. Not sure what the problem is. Any incite? The raw_dma_adc[] array has no values in it during debug.
The code is for a STM32F051K6U6. End goal is to have 5 channels running. GPIO clock for port A has been enabled.///////////////////////ADC
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2| GPIO_Pin_3 | GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);ADC_DeInit(ADC1);
DMA_DeInit(DMA1);ADC_InitTypeDef Impac_ADC;
Impac_ADC.ADC_Resolution = ADC_Resolution_12b; Impac_ADC.ADC_ContinuousConvMode = ENABLE; Impac_ADC.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; Impac_ADC.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_TRGO; //not used Impac_ADC.ADC_DataAlign = ADC_DataAlign_Right; Impac_ADC.ADC_ScanDirection = ADC_ScanDirection_Backward; ADC_Init(ADC1, &Impac_ADC);ADC_ChannelConfig(ADC1, ADC_Channel_0, ADC_SampleTime_239_5Cycles);
ADC_ChannelConfig(ADC1, ADC_Channel_1, ADC_SampleTime_239_5Cycles);
//Calibrate ADC. This must be done before enabling the ADC. The function has a delay built in to allow for wait for calibration.
ADC_GetCalibrationFactor(ADC1);ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
DMA_InitTypeDef Impac_DMA;
Impac_DMA.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; Impac_DMA.DMA_MemoryBaseAddr = (uint32_t)&raw_dma_adc[0]; Impac_DMA.DMA_DIR = DMA_DIR_PeripheralSRC;//? //DMA_DIR_PeripheralSRC; Impac_DMA.DMA_BufferSize = 2; Impac_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //Keep incrimenting pointer to ADC buffer as tranfering. Impac_DMA.DMA_MemoryInc = DMA_MemoryInc_Enable; //Keep incrimenting pointer to DMA mem Impac_DMA.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; Impac_DMA.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; Impac_DMA.DMA_Mode = DMA_Mode_Circular; Impac_DMA.DMA_Priority = DMA_Priority_High; Impac_DMA.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1, &Impac_DMA); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE);ADC_StartOfConversion(ADC1);
2014-03-26 09:06 AM
Let's begin with changing
Impac_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //Keep incrimenting pointer to ADC buffer as tranfering. with non-incrementing configuration, so the DMA always read the DR register.2014-03-26 09:35 AM
That, and probably not 32-bit words either.
// STM32 ADC 4 Channel DMA/TIM STM32F0-Discovery sourcer32@gmail.com
#include ''stm32f0xx.h''
//**************************************************************************************
#define SAMPLES 200
__IO uint16_t RegularConvData[SAMPLES]; // 100 Samples to half, 25 x 4, Calls IRQ at 40 Hz
void ADC_TIM_DMA_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* ADC1 DeInit */
ADC_DeInit(ADC1);
/* ADC1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1, ENABLE);
/* DMA1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* TIM2 Configuration */
TIM_DeInit(TIM1);
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz
TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 1 KHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Output Compare PWM Mode configuration */
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /* low edge by default */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0x01;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
/* Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
/* DMA1 Channel1 Config */
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&RegularConvData[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = SAMPLES;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* DMA1 Channel1 enable */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC DMA request in circular mode */
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
/* Enable DMA1 Channel1 Half Transfer and Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel1, DMA_IT_HT, ENABLE);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
/* Enable ADC_DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);
/* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure);
/* Convert the ADC_Channnel_0 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_1 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_2 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_2 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_3 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_3 , ADC_SampleTime_7_5Cycles);
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Wait the ADCEN flag */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
/* ADC1 regular Software Start Conv */
ADC_StartOfConversion(ADC1);
}
//**************************************************************************************
void DMA1_Channel1_IRQHandler(void) // Called at 40 Hz, LED Toggles at 20 Hz
{
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if (DMA_GetITStatus(DMA1_IT_HT1))
{
/* Clear DMA1 Channel1 Half Transfer interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_HT1);
GPIOC->BSRR = 0x300; /* Set PC8 and PC9 */
}
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if (DMA_GetITStatus(DMA1_IT_TC1))
{
/* Clear DMA1 Channel1 Transfer Complete interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_TC1);
GPIOC->BRR = 0x300;/* Reset PC8 and PC9 */
}
}
//**************************************************************************************
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable and set DMA1_Channel1 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//**************************************************************************************
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOC Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
/* Configure PC8 and PC9 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* GPIOA Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure ADC Channels as analog input - might conflict */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//**************************************************************************************
int main(void)
{
NVIC_Config();
GPIO_Config();
ADC_TIM_DMA_Config();
while(1); /* Infinite loop */
}
//**************************************************************************************
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d
'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
//**************************************************************************************
2014-03-26 09:43 AM
// STM32 ADC 5 Channel DMA/TIM STM32F0-Discovery sourcer32@gmail.com
#include ''stm32f0xx.h''
//**************************************************************************************
#define SAMPLES 2500
__IO uint16_t RegularConvData[SAMPLES]; // 1250 Samples to half, 250 x 5, Calls IRQ at 4 Hz (1KHZ/250)
void ADC_TIM_DMA_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
/* ADC1 DeInit */
ADC_DeInit(ADC1);
/* ADC1 Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1, ENABLE);
/* DMA1 clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* TIM2 Configuration */
TIM_DeInit(TIM1);
/* Time base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 1000000) - 1; // 1 MHz, from 48 MHz
TIM_TimeBaseStructure.TIM_Period = 1000 - 1; // 1 KHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Output Compare PWM Mode configuration */
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /* low edge by default */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0x01;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 enable counter */
TIM_Cmd(TIM1, ENABLE);
/* Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, ENABLE);
/* DMA1 Channel1 Config */
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&RegularConvData[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = SAMPLES;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* DMA1 Channel1 enable */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* ADC DMA request in circular mode */
ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
/* Enable DMA1 Channel1 Half Transfer and Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel1, DMA_IT_HT, ENABLE);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
/* Enable ADC_DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Initialize ADC structure */
ADC_StructInit(&ADC_InitStructure);
/* Configure the ADC1 in continous mode withe a resolutuion equal to 12 bits */
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;
ADC_Init(ADC1, &ADC_InitStructure);
/* Convert the ADC_Channnel_0 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_0 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_1 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_1 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_2 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_2 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_3 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_3 , ADC_SampleTime_7_5Cycles);
/* Convert the ADC_Channnel_4 with 7.5 Cycles as sampling time */
ADC_ChannelConfig(ADC1, ADC_Channel_4 , ADC_SampleTime_7_5Cycles);
/* ADC Calibration */
ADC_GetCalibrationFactor(ADC1);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Wait the ADCEN flag */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));
/* ADC1 regular Software Start Conv */
ADC_StartOfConversion(ADC1);
}
//**************************************************************************************
void DMA1_Channel1_IRQHandler(void) // Called at 4 Hz, LED Toggles at 2 Hz
{
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if (DMA_GetITStatus(DMA1_IT_HT1))
{
/* Clear DMA1 Channel1 Half Transfer interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_HT1);
GPIOC->BSRR = 0x100; /* Set PC8 */
GPIOC->BRR = 0x200;/* Reset PC9 */
}
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if (DMA_GetITStatus(DMA1_IT_TC1))
{
/* Clear DMA1 Channel1 Transfer Complete interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_TC1);
GPIOC->BSRR = 0x200; /* Set PC9 */
GPIOC->BRR = 0x100;/* Reset PC8 */
}
}
//**************************************************************************************
void NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable and set DMA1_Channel1 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//**************************************************************************************
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* GPIOC Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
/* Configure PC8 and PC9 in output pushpull mode */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* GPIOA Periph clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Configure ADC Channels as analog input - might conflict */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
//**************************************************************************************
int main(void)
{
NVIC_Config();
GPIO_Config();
ADC_TIM_DMA_Config();
while(1); /* Infinite loop */
}
//**************************************************************************************
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d
'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
//**************************************************************************************
2014-03-26 11:00 AM
Thank you for the replies. I have tried making the requested changes, excluding adding interrupt to DMA. I will try this though.
I changed the word size to half, Impac_DMA.DMA_PeripheralInc = DMA_PeripheralInc_Disable, and changed the counting to upward. I should note that I am doing nothing in my main loop. I am just watching the array where the data should be transferred to expecting to see something when the program runs. I made all of these individually hoping one of them alone was an issue. I am surprised to not see any DMA transfer. This worked great for me on the STM32F1. Any other ideas?2014-03-26 12:19 PM
DMA_DeInit(DMA1, &Impac_DMA); DMA_Init(DMA1, &Impac_DMA);
DMA1_Channel1 ??2014-03-28 07:02 AM
Clive - still no luck.
I copied in your example code and it works. I removed the interrupt - still works. When I attempt to remove timer 1, or even just /* Output Compare PWM Mode configuration */ TIM_OCStructInit(&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; /* low edge by default */ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 0x01; TIM_OC4Init(TIM1, &TIM_OCInitStructure); /* Main Output Enable */ TIM_CtrlPWMOutputs(TIM1, ENABLE); the DMA does not work. I do not understand why the DMA needs the pwm output compare or TIM1 for successful operation? Can you explain this?2014-03-28 07:18 AM
I am pacing the sampling at a designated frequency, rather than attempting to free run the ADC.
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC4;
2014-03-31 07:55 AM
2014-06-06 12:06 AM