From: drowe67 Date: Wed, 12 Jun 2013 02:12:43 +0000 (+0000) Subject: ADC DMA now working X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=5c3df4f2620b1914e42528c4332a4e9a2db031aa;p=freetel-svn-tracking.git ADC DMA now working git-svn-id: https://svn.code.sf.net/p/freetel/code@1314 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/stm32/Makefile b/codec2-dev/stm32/Makefile index 9fa38861..d93056ed 100644 --- a/codec2-dev/stm32/Makefile +++ b/codec2-dev/stm32/Makefile @@ -163,7 +163,7 @@ src/startup_stm32f4xx.s \ src/init.c adc_ut.elf: $(ADC_UT_SRCS) - $(CC) $(CFLAGS) -O0 $^ -o $@ $(LIBPATHS) $(LIBS) + $(CC) $(CFLAGS) $^ -o $@ $(LIBPATHS) $(LIBS) clean: rm -f *.o diff --git a/codec2-dev/stm32/src/stm32f4_adc.c b/codec2-dev/stm32/src/stm32f4_adc.c index bebd157f..9c6a17dc 100644 --- a/codec2-dev/stm32/src/stm32f4_adc.c +++ b/codec2-dev/stm32/src/stm32f4_adc.c @@ -36,26 +36,240 @@ #include #include #include -#include "stm32f4xx.h" #include "codec2_fifo.h" -#include "stm32f4_adc.h" +#include "gdb_stdio.h" +#include "stm32f4xx_adc.h" +#include "stm32f4xx_gpio.h" +#include "stm32f4xx_rcc.h" + +//#define TRY3 +#ifdef TRY3 + +#define ADCx ADC1 +#define ADCx_CLK RCC_APB2Periph_ADC1 +#define DMA_CHANNELx DMA_Channel_0 +#define DMA_STREAMx DMA2_Stream0 +#define ADCx_DR_ADDRESS ((uint32_t)0x4001204C) + +static void ADC_Config(void); + +volatile unsigned short uhADCConvertedValue[10]; + +int adc_convert(){ + while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion + return ADC_GetConversionValue(ADC1); //Return the converted data +} + +int main(void) +{ + + /* ADC1 Channel Vbat configuration */ + ADC_Config(); + + /* Start ADC1 Software Conversion */ + ADC_SoftwareStartConv(ADC1); + + while (1) { + //uhADCConvertedValue = adc_convert(); + int i; + for(i=0; i<10; i++) + printf("ADC: %d \n", uhADCConvertedValue[i]); + } +} + +static void ADC_Config(void); + +/** + * @brief ADC1 Channel Vbat configuration + * @note This function Configure the ADC peripheral + 1) Enable peripheral clocks + 2) DMA2_Stream0 channel 0 configuration + 3) Configure ADC1 Channel18 (VBAT) + * @param None + * @retval None + */ +static void ADC_Config(void) +{ + ADC_InitTypeDef ADC_InitStructure; + ADC_CommonInitTypeDef ADC_CommonInitStructure; + DMA_InitTypeDef DMA_InitStructure; + + /* Enable peripheral clocks *************************************************/ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE); -#define ADCx ADC3 + /* DMA2_Stream0 channel0 configuration **************************************/ + DMA_DeInit(DMA2_Stream0); + DMA_InitStructure.DMA_Channel = DMA_CHANNELx; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADCConvertedValue; + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; + DMA_InitStructure.DMA_BufferSize = 10; + 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_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_Init(DMA_STREAMx, &DMA_InitStructure); + + /* DMA2_Stream0 enable */ + DMA_Cmd(DMA_STREAMx, ENABLE); + + /* ADC Common Init **********************************************************/ + ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; + ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; + ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; + ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; + ADC_CommonInit(&ADC_CommonInitStructure); + + /* ADC1 Init ****************************************************************/ + ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; + ADC_InitStructure.ADC_ScanConvMode = DISABLE; + ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; + ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; + ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; + ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; + ADC_InitStructure.ADC_NbrOfConversion = 1; + ADC_Init(ADCx, &ADC_InitStructure); + + /* Enable ADC1 DMA */ + ADC_DMACmd(ADCx, ENABLE); + +#define VBAT +#ifdef VBAT + /* ADC1 regular channel18 (VBAT) configuration ******************************/ + ADC_RegularChannelConfig(ADCx, ADC_Channel_Vbat, 1, ADC_SampleTime_15Cycles); + + /* Enable VBAT channel */ + ADC_VBATCmd(ENABLE); +#else + ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, 1, ADC_SampleTime_15Cycles); + ADC_TempSensorVrefintCmd(ENABLE); +#endif + + /* Enable DMA request after last transfer (Single-ADC mode) */ + ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE); + + /* Enable ADC1 **************************************************************/ + ADC_Cmd(ADCx, ENABLE); +} +#endif + +#define TRY2 +#ifdef TRY2 + +int ConvertedValue = 0; //Converted value readed from ADC +#define ADCx_DR_ADDRESS ((uint32_t)0x4001204C) +volatile unsigned short uhADCxConvertedValue[10]; + +#define DMA_CHANNELx DMA_Channel_0 +#define DMA_STREAMx DMA2_Stream0 + + ADC_InitTypeDef ADC_init_structure; //Structure for adc confguration + GPIO_InitTypeDef GPIO_initStructre; //Structure for analog input pin + DMA_InitTypeDef DMA_InitStructure; + +void adc_configure(){ + + + //Clock configuration + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//The ADC1 is connected the APB2 peripheral bus thus we will use its clock source + RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIOCEN,ENABLE);//Clock for the ADC port!! Do not forget about this one ;) + + /* DMA2 configuration **************************************/ + DMA_InitStructure.DMA_Channel = DMA_CHANNELx; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADCxConvertedValue; + DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; + DMA_InitStructure.DMA_BufferSize = 10; + 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_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_Init(DMA_STREAMx, &DMA_InitStructure); + DMA_Cmd(DMA_STREAMx, ENABLE); + + //Analog pin configuration + GPIO_initStructre.GPIO_Pin = GPIO_Pin_0;//The channel 10 is connected to PC0 + GPIO_initStructre.GPIO_Mode = GPIO_Mode_AN; //The PC0 pin is configured in analog mode + GPIO_initStructre.GPIO_PuPd = GPIO_PuPd_NOPULL; //We don't need any pull up or pull down + GPIO_Init(GPIOC,&GPIO_initStructre);//Affecting the port with the initialization structure configuration + + //ADC structure configuration + ADC_DeInit(); + ADC_init_structure.ADC_DataAlign = ADC_DataAlign_Right;//data converted will be shifted to right + ADC_init_structure.ADC_Resolution = ADC_Resolution_12b;//Input voltage is converted into a 12bit number giving a maximum value of 4096 + ADC_init_structure.ADC_ContinuousConvMode = ENABLE; //the conversion is continuous, the input data is converted more than once + ADC_init_structure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;// conversion is synchronous with TIM1 and CC1 (actually I'm not sure about this one :/) + ADC_init_structure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//no trigger for conversion + ADC_init_structure.ADC_NbrOfConversion = 1;//I think this one is clear :p + ADC_init_structure.ADC_ScanConvMode = DISABLE;//The scan is configured in one channel + ADC_Init(ADC1,&ADC_init_structure);//Initialize ADC with the previous configuration + + /* Enable DMA request after last transfer (Single-ADC mode) */ + ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); + + /* Enable ADC1 DMA */ + ADC_DMACmd(ADC1, ENABLE); + + //Enable ADC conversion + ADC_Cmd(ADC1,ENABLE); + + //Select the channel to be read from + ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_144Cycles); +} + +int adc_convert(){ + while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));//Processing the conversion + return ADC_GetConversionValue(ADC1); //Return the converted data +} + +int main(void){ + adc_configure();//Start configuration + ADC_SoftwareStartConv(ADC1);//Start the conversion + while(1){//loop while the board is working + //ConvertedValue = adc_convert();//Read the ADC converted value + //printf("ConvertedValue = %d\n", ConvertedValue); + int i; + for(i=0; i<10; i++) + printf("ADC: %d \n", uhADCxConvertedValue[i]); + } +} +#endif + +#ifdef TRY1 + +#define ADCx ADC1 #define ADC_CHANNEL ADC_Channel_7 -#define ADCx_CLK RCC_APB2Periph_ADC3 -#define ADCx_CHANNEL_GPIO_CLK RCC_AHB1Periph_GPIOF -#define GPIO_PIN GPIO_Pin_9 -#define GPIO_PORT GPIOF -#define DMA_CHANNELx DMA_Channel_2 +#define ADCx_CLK RCC_APB2Periph_ADC1 +#define ADCx_CHANNEL_GPIO_CLK RCC_AHB1Periph_GPIOA +#define GPIO_PIN GPIO_Pin_7 +#define GPIO_PORT GPIOA +#define DMA_CHANNELx DMA_Channel_0 #define DMA_STREAMx DMA2_Stream0 -#define ADCx_DR_ADDRESS ((uint32_t)0x4001224C) +#define ADCx_DR_ADDRESS ((uint32_t)0x4001204C) -#define TIM1_CCR3_ADDRESS 0x4001003C +#define TIM1_CCR3_ADDRESS 0x4001223C TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; +uint16_t uhTimerPeriod; +uint16_t aSRC_Buffer[3] = {0, 0, 0}; + unsigned short uhADCxConvertedValue; static void ADC_Config(void); @@ -67,13 +281,14 @@ int main(void) { /* look for 17kHz (ish) on timer pins */ ADC_Config(); + ADC_SoftwareStartConv(ADCx); Timer1Config(); /* todo: that start up cmd here */ while(1) { - printf("ADC; %d\n", uhADCxConvertedValue); + printf("ADC: %d\n", uhADCxConvertedValue); } } @@ -158,86 +373,86 @@ static void ADC_Config(void) void Timer1Config() { - /* TIM Configuration */ + /* TIM Configuration */ - TIM_Config(); + TIM_Config(); - /* TIM1 DMA Transfer example ------------------------------------------------- + /* TIM1 DMA Transfer example ------------------------------------------------- - TIM1 input clock (TIM1CLK) is set to 2 * APB2 clock (PCLK2), since APB2 - prescaler is different from 1. - TIM1CLK = 2 * PCLK2 - PCLK2 = HCLK / 2 - => TIM1CLK = 2 * (HCLK / 2) = HCLK = SystemCoreClock + TIM1 input clock (TIM1CLK) is set to 2 * APB2 clock (PCLK2), since APB2 + prescaler is different from 1. + TIM1CLK = 2 * PCLK2 + PCLK2 = HCLK / 2 + => TIM1CLK = 2 * (HCLK / 2) = HCLK = SystemCoreClock - TIM1CLK = SystemCoreClock, Prescaler = 0, TIM1 counter clock = SystemCoreClock - SystemCoreClock is set to 168 MHz for STM32F4xx devices. - - The objective is to configure TIM1 channel 3 to generate complementary PWM - signal with a frequency equal to 17.57 KHz: - - TIM1_Period = (SystemCoreClock / 17570) - 1 - and a variable duty cycle that is changed by the DMA after a specific number of - Update DMA request. - - The number of this repetitive requests is defined by the TIM1 Repetion counter, - each 3 Update Requests, the TIM1 Channel 3 Duty Cycle changes to the next new - value defined by the aSRC_Buffer. + TIM1CLK = SystemCoreClock, Prescaler = 0, TIM1 counter clock = SystemCoreClock + SystemCoreClock is set to 168 MHz for STM32F4xx devices. + + The objective is to configure TIM1 channel 3 to generate complementary PWM + signal with a frequency equal to 17.57 KHz: + - TIM1_Period = (SystemCoreClock / 17570) - 1 + and a variable duty cycle that is changed by the DMA after a specific number of + Update DMA request. + + The number of this repetitive requests is defined by the TIM1 Repetion counter, + each 3 Update Requests, the TIM1 Channel 3 Duty Cycle changes to the next new + value defined by the aSRC_Buffer. - Note: - SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file. - Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate() - function to update SystemCoreClock variable value. Otherwise, any configuration - based on this variable will be incorrect. - -----------------------------------------------------------------------------*/ + Note: + SystemCoreClock variable holds HCLK frequency and is defined in system_stm32f4xx.c file. + Each time the core clock (HCLK) changes, user had to call SystemCoreClockUpdate() + function to update SystemCoreClock variable value. Otherwise, any configuration + based on this variable will be incorrect. + -----------------------------------------------------------------------------*/ - /* Compute the value to be set in ARR regiter to generate signal frequency at 17.57 Khz */ - uhTimerPeriod = (SystemCoreClock / 17570 ) - 1; - /* Compute CCR1 value to generate a duty cycle at 50% */ - aSRC_Buffer[0] = (uint16_t) (((uint32_t) 5 * (uhTimerPeriod - 1)) / 10); - /* Compute CCR1 value to generate a duty cycle at 37.5% */ - aSRC_Buffer[1] = (uint16_t) (((uint32_t) 375 * (uhTimerPeriod - 1)) / 1000); - /* Compute CCR1 value to generate a duty cycle at 25% */ - aSRC_Buffer[2] = (uint16_t) (((uint32_t) 25 * (uhTimerPeriod - 1)) / 100); - - /* TIM1 Peripheral Configuration -------------------------------------------*/ - /* TIM1 clock enable */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); - - /* Time Base configuration */ - TIM_TimeBaseStructure.TIM_Prescaler = 0; - TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; - TIM_TimeBaseStructure.TIM_Period = uhTimerPeriod; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; - TIM_TimeBaseStructure.TIM_RepetitionCounter = 3; - - TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); - - /* Channel 3 Configuration in PWM mode */ - TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; - TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; - TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; - TIM_OCInitStructure.TIM_Pulse = aSRC_Buffer[0]; - TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; - TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low; - TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; - TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; - - TIM_OC3Init(TIM1, &TIM_OCInitStructure); - - /* Enable preload feature */ - TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); + /* Compute the value to be set in ARR regiter to generate signal frequency at 17.57 Khz */ + uhTimerPeriod = (SystemCoreClock / 17570 ) - 1; + /* Compute CCR1 value to generate a duty cycle at 50% */ + aSRC_Buffer[0] = (uint16_t) (((uint32_t) 5 * (uhTimerPeriod - 1)) / 10); + /* Compute CCR1 value to generate a duty cycle at 37.5% */ + aSRC_Buffer[1] = (uint16_t) (((uint32_t) 375 * (uhTimerPeriod - 1)) / 1000); + /* Compute CCR1 value to generate a duty cycle at 25% */ + aSRC_Buffer[2] = (uint16_t) (((uint32_t) 25 * (uhTimerPeriod - 1)) / 100); + + /* TIM1 Peripheral Configuration -------------------------------------------*/ + /* TIM1 clock enable */ + RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); + + /* Time Base configuration */ + TIM_TimeBaseStructure.TIM_Prescaler = 0; + TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; + TIM_TimeBaseStructure.TIM_Period = uhTimerPeriod; + TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_RepetitionCounter = 3; + + TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); + + /* Channel 3 Configuration in PWM mode */ + TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; + TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; + TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; + TIM_OCInitStructure.TIM_Pulse = aSRC_Buffer[0]; + TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; + TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low; + TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; + TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; + + TIM_OC3Init(TIM1, &TIM_OCInitStructure); + + /* Enable preload feature */ + TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable); - /* TIM1 counter enable */ - TIM_Cmd(TIM1, ENABLE); + /* TIM1 counter enable */ + TIM_Cmd(TIM1, ENABLE); - /* DMA enable*/ - DMA_Cmd(DMA2_Stream6, ENABLE); + /* DMA enable*/ + DMA_Cmd(DMA2_Stream6, ENABLE); - /* TIM1 Update DMA Request enable */ - TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE); + /* TIM1 Update DMA Request enable */ + TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE); - /* Main Output Enable */ - TIM_CtrlPWMOutputs(TIM1, ENABLE); + /* Main Output Enable */ + TIM_CtrlPWMOutputs(TIM1, ENABLE); } /* DR: note I dont think any of this is needed, except perhaps to check @@ -292,3 +507,4 @@ static void TIM_Config(void) DMA_Init(DMA2_Stream6, &DMA_InitStructure); } +#endif