2015-04-23 10:13 PM
Hi, I would like to ask how to sample adc values (potentiometer) using DMA interrupt?
#adc #dma #stm32f3discovery2015-04-24 09:01 AM
Quick blind example, should be serviceable.
// STM32 ADC Single Channel DMA STM32F3-Discovery - sourcer32@gmail.com
/**************************************************************************************/
// ADC1 ADC2 ADC3 ADC4
// IN1 PA0* PA4 PB1 PE14*
// IN2 PA1 PA5* PE9* PE15*
// IN3 PA2 PA6* PE13* PB12
// IN4 PA3 PA7* --- PB14
// IN5 PF4 PC4 PB13 PB15
//
// *Used on STM32F3-Discovery
// Free pins located in STM32F3-Discovery manual, UM1570
/**************************************************************************************/
#include ''stm32f3_discovery.h''
#include ''stm32f30x.h''
#include <
stdio.h
>
/**************************************************************************************/
#define BUFSIZE 1 // Small for no useful reason
volatile uint16_t ADCConvertedValues[BUFSIZE];
uint16_t CalibrationValue;
/**************************************************************************************/
void ADC_GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOA Periph clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* ADC Channels configuration */
/* Configure PA1 as analog input */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void ADC12_DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* Enable DMA1 clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* DMA configuration */
/* DMA1 Channel1 Init Test */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // The register of a singular ADC
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValues[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BUFSIZE;
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_Medium;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure); // ADC1
}
/**************************************************************************************/
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
volatile int i;
/* Configure the ADC clocks */
RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);
/* Enable ADC1/2 clocks */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);
/* ADC GPIO configuration */
ADC_GPIO_Configuration();
/* ADC DMA Channel configuration */
ADC12_DMA_Configuration();
/* ADC Calibration procedure */
ADC_VoltageRegulatorCmd(ADC1, ENABLE);
/* Insert delay equal to 10 µs */
for(i=0; i<
10000
; i++);
ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) != RESET);
CalibrationValue
=
ADC_GetCalibrationValue
(ADC1);
/* ADC configuration */
ADC_CommonInitStructure.ADC_Mode
=
ADC_Mode_Independent
;
ADC_CommonInitStructure.ADC_Clock
=
ADC_Clock_AsynClkMode
;
ADC_CommonInitStructure.ADC_DMAAccessMode
=
ADC_DMAAccessMode_Disabled
; // Not Multi Mode
ADC_CommonInitStructure.ADC_DMAMode
=
ADC_DMAMode_Circular
;
ADC_CommonInitStructure.ADC_TwoSamplingDelay
=
10
;
ADC_CommonInit(ADC1, &ADC_CommonInitStructure);
/* */
ADC_InitStructure.ADC_ContinuousConvMode
=
ADC_ContinuousConvMode_Enable
; // Freerun
ADC_InitStructure.ADC_Resolution
=
ADC_Resolution_12b
;
ADC_InitStructure.ADC_ExternalTrigConvEvent
=
ADC_ExternalTrigConvEvent_0
; // Not using
ADC_InitStructure.ADC_ExternalTrigEventEdge
=
ADC_ExternalTrigEventEdge_None
;
ADC_InitStructure.ADC_DataAlign
=
ADC_DataAlign_Right
;
ADC_InitStructure.ADC_OverrunMode
=
ADC_OverrunMode_Disable
;
ADC_InitStructure.ADC_AutoInjMode
=
ADC_AutoInjec_Disable
;
ADC_InitStructure.ADC_NbrOfRegChannel
=
1
;
ADC_Init(ADC1, &ADC_InitStructure);
/* ADC1 regular configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_61Cycles5); // PA1
/* Configures the ADC DMA */
ADC_DMAConfig(ADC1, ADC_DMAMode_Circular);
/* Enable the ADC DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* wait for ADC1 ADRDY */
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_RDY));
/* Enable the DMA channel */
DMA_Cmd(DMA1_Channel1, ENABLE);
/* Enable DMA1 Channel1 Transfer Complete interrupt */
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
/* Start ADC1 Software Conversion */
ADC_StartConversion(ADC1);
}
/**************************************************************************************/
void DMA1_Channel1_IRQHandler(void) // X Hz
{
/* Test on DMA1 Channel1 Transfer Complete interrupt */
if(DMA_GetITStatus(DMA1_IT_TC1))
{
/* Clear DMA1 Channel1 Half Transfer, Transfer Complete and Global interrupt pending bits */
DMA_ClearITPendingBit(DMA1_IT_GL1);
STM_EVAL_LEDToggle(LED3); // X/2 Hz
}
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the DMA1 CH1 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel
=
DMA1_Channel1_IRQn
;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority
=
0
;
NVIC_InitStructure.NVIC_IRQChannelSubPriority
=
1
;
NVIC_InitStructure.NVIC_IRQChannelCmd
=
ENABLE
;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
int main(void)
{
/* Initialize LEDs available on STM32F-Discovery board */
STM_EVAL_LEDInit(LED3);
STM_EVAL_LEDInit(LED4);
/* Turn on LD3 */
STM_EVAL_LEDOn(LED3);
STM_EVAL_LEDOn(LED4);
NVIC_Configuration();
ADC_Configuration();
while(1) // Don't want to exit
{
if (ADCConvertedValues[0] != 0xFFFF)
{
printf(''%03
X'', ADCConvertedValues[0]);
ADCConvertedValues[0] = 0xFFFF;
}
}
}
//******************************************************************************
// Rough SWV support in Keil, STM32F3-Discovery, Make SB10 to connect PB3/SWO
//******************************************************************************
#include <rt_misc.h>
#pragma import(__use_no_semihosting_swi)
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f)
{
ITM_SendChar(ch);
return(ch);
}
int fgetc(FILE *f)
{
char ch;
ch = 1;
return((int)ch);
}
int ferror(FILE *f)
{
/* Your implementation of ferror */
return EOF;
}
void _ttywrch(int ch)
{
ITM_SendChar(ch);
}
void _sys_exit(int return_code)
{
label: goto label; /* endless 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
//******************************************************************************