From: drowe67 Date: Tue, 4 Jun 2013 05:29:43 +0000 (+0000) Subject: started coding STM32 ADC driver X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=69038d156169da166502bc141d55deadd58e040c;p=freetel-svn-tracking.git started coding STM32 ADC driver git-svn-id: https://svn.code.sf.net/p/freetel/code@1309 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/codec2-dev/stm32/inc/gdb_stdio.h b/codec2-dev/stm32/inc/gdb_stdio.h index 1b38f55f..eafabca4 100644 --- a/codec2-dev/stm32/inc/gdb_stdio.h +++ b/codec2-dev/stm32/inc/gdb_stdio.h @@ -38,4 +38,10 @@ void gdb_stdio_fclose(FILE *file); int gdb_stdio_fwrite(void *ptr, int size, int nmemb, FILE *file); int gdb_stdio_fread(void *ptr, int size, int nmemb, FILE *file); +#define printf gdb_stdio_printf +#define fopen gdb_stdio_fopen +#define fclose gdb_stdio_fclose +#define fread gdb_stdio_fread +#define fwrite gdb_stdio_fwrite + #endif diff --git a/codec2-dev/stm32/src/dac_play.c b/codec2-dev/stm32/src/dac_play.c index 3e08abbd..aa69f332 100644 --- a/codec2-dev/stm32/src/dac_play.c +++ b/codec2-dev/stm32/src/dac_play.c @@ -29,12 +29,6 @@ #include "stm32f4_dac.h" #include "gdb_stdio.h" -#define printf gdb_stdio_printf -#define fopen gdb_stdio_fopen -#define fclose gdb_stdio_fclose -#define fread gdb_stdio_fread -#define fwrite gdb_stdio_fwrite - #define N 2000 int main(void) { diff --git a/codec2-dev/stm32/src/stm32f4_adc.c b/codec2-dev/stm32/src/stm32f4_adc.c new file mode 100644 index 00000000..e0fb5e99 --- /dev/null +++ b/codec2-dev/stm32/src/stm32f4_adc.c @@ -0,0 +1,281 @@ +/*---------------------------------------------------------------------------*\ + + FILE........: stm32f4_adc.c + AUTHOR......: David Rowe + DATE CREATED: 4 June 2013 + + ADC driver module for STM32F4. + + TODO: + + just get ADC to run at all, prove its sampling something.... + + timer config to drive ADC conversion, measure sample rate and confirm 16kHz + + larger ADC DMA buffer + + half and finished interrupts, ISR + + fifos + + work out a way to unit test + +\*---------------------------------------------------------------------------*/ + +/* + Copyright (C) 2013 David Rowe + + All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1, as + published by the Free Software Foundation. This program is + distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include "stm32f4xx.h" +#include "codec2_fifo.h" +#include "stm32f4_adc.h" + + +#define ADCx ADC3 +#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 DMA_STREAMx DMA2_Stream0 +#define ADCx_DR_ADDRESS ((uint32_t)0x4001224C) + +#define TIM1_CCR3_ADDRESS 0x4001003C + +TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; +TIM_OCInitTypeDef TIM_OCInitStructure; + +static void ADC_Config(void); +void Timer1Config(); +static void TIM_Config(void); + +int main(void) { + ADC_Config(); + +} + +/** + * @brief ADC3 channel07 with DMA configuration + * @note This function Configure the ADC peripheral + 1) Enable peripheral clocks + 2) DMA2_Stream0 channel2 configuration + 3) Configure ADC Channel7 pin as analog input + 4) Configure ADC3 Channel7 + * @param None + * @retval None + */ +static void ADC_Config(void) +{ + ADC_InitTypeDef ADC_InitStructure; + ADC_CommonInitTypeDef ADC_CommonInitStructure; + DMA_InitTypeDef DMA_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; + + /* Enable ADCx, DMA and GPIO clocks ****************************************/ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); + RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE); + RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE); + + + /* DMA2 Stream0 channel2 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 = 1; + DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; + DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; + 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); + + /* Configure ADC3 Channel7 pin as analog input ******************************/ + GPIO_InitStructure.GPIO_Pin = GPIO_PIN; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; + GPIO_Init(GPIO_PORT, &GPIO_InitStructure); + + /* 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); + + /* ADC3 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); + + /* ADC3 regular channel7 configuration *************************************/ + ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_3Cycles); + + /* Enable DMA request after last transfer (Single-ADC mode) */ + ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE); + + /* Enable ADC3 DMA */ + ADC_DMACmd(ADCx, ENABLE); + + /* Enable ADC3 */ + ADC_Cmd(ADCx, ENABLE); +} + +void Timer1Config() { + + /* TIM Configuration */ + + TIM_Config(); + + /* 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 + + 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. + -----------------------------------------------------------------------------*/ + + /* 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); + + /* DMA enable*/ + DMA_Cmd(DMA2_Stream6, ENABLE); + + /* TIM1 Update DMA Request enable */ + TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE); + + /* Main Output Enable */ + TIM_CtrlPWMOutputs(TIM1, ENABLE); +} + +/* DR: note I dont think any of this is needed, except perhaps to check + timer frequency */ + +/** + * @brief Configure the TIM1 Pins. + * @param None + * @retval None + */ +static void TIM_Config(void) +{ + GPIO_InitTypeDef GPIO_InitStructure; + DMA_InitTypeDef DMA_InitStructure; + + /* GPIOA and GPIOB clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE); + + /* GPIOA Configuration: Channel 3 as alternate function push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 ; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; + GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; + GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; + GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; + GPIO_Init(GPIOA, &GPIO_InitStructure); + GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_TIM1); + + /* GPIOB Configuration: Channel 3N as alternate function push-pull */ + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; + GPIO_Init(GPIOB, &GPIO_InitStructure); + GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_TIM1); + + /* DMA clock enable */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2 , ENABLE); + + DMA_DeInit(DMA2_Stream6); + DMA_InitStructure.DMA_Channel = DMA_Channel_6; + DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(TIM1_CCR3_ADDRESS) ; + DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aSRC_Buffer; + DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; + DMA_InitStructure.DMA_BufferSize = 3; + 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_PeripheralDataSize_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_Full; + DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; + DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; + + DMA_Init(DMA2_Stream6, &DMA_InitStructure); +}