paparazzi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[paparazzi-commits] [5683] Added STM32 ADC driver ( 4-channel injection


From: Tobias Fuchs
Subject: [paparazzi-commits] [5683] Added STM32 ADC driver ( 4-channel injection triggered by timer 2 or 4).
Date: Wed, 25 Aug 2010 23:32:27 +0000

Revision: 5683
          http://svn.sv.gnu.org/viewvc/?view=rev&root=paparazzi&revision=5683
Author:   fuchsto
Date:     2010-08-25 23:32:26 +0000 (Wed, 25 Aug 2010)
Log Message:
-----------
Added STM32 ADC driver (4-channel injection triggered by timer 2 or 4). 

Modified Paths:
--------------
    paparazzi3/trunk/conf/autopilot/lisa_test_progs.makefile
    paparazzi3/trunk/sw/airborne/adc.h
    paparazzi3/trunk/sw/airborne/lisa/test_csc_servo.c
    paparazzi3/trunk/sw/airborne/stm32/adc_hw.c

Added Paths:
-----------
    paparazzi3/trunk/sw/airborne/lisa/test_adc.c

Modified: paparazzi3/trunk/conf/autopilot/lisa_test_progs.makefile
===================================================================
--- paparazzi3/trunk/conf/autopilot/lisa_test_progs.makefile    2010-08-25 
23:25:33 UTC (rev 5682)
+++ paparazzi3/trunk/conf/autopilot/lisa_test_progs.makefile    2010-08-25 
23:32:26 UTC (rev 5683)
@@ -1276,37 +1276,58 @@
 #
 # test ADC
 #
+#      test_adc.ARCHDIR = $(ARCHI)
+#      test_adc.TARGET = test_adc
+#      test_adc.TARGETDIR = test_adc
+#      test_adc.CFLAGS = -I$(ARCHI) -DPERIPHERALS_AUTO_INIT
+#      test_adc.CFLAGS += -DBOARD_CONFIG=$(BOARD_CFG) -I$(SRC_BOOZ) 
-I$(SRC_BOOZ_ARCH)
+#      test_adc.srcs += $(SRC_LISA)/test/lisa_test_adc.c \
+#                       $(SRC_ARCH)/stm32_exceptions.c   \
+#                       $(SRC_ARCH)/stm32_vector_table.c
+#      test_adc.CFLAGS += -DUSE_LED
+#      test_adc.srcs += $(SRC_ARCH)/led_hw.c
+#      test_adc.CFLAGS += -DUSE_SYS_TIME -DSYS_TIME_LED=1
+#      test_adc.CFLAGS += -DPERIODIC_TASK_PERIOD='SYS_TICS_OF_SEC((1./512.))' 
-DTIME_LED=1
+#      test_adc.srcs += sys_time.c $(SRC_ARCH)/sys_time_hw.c
+#      
+#      test_adc.CFLAGS += -DUSE_UART2 -DUART2_BAUD=B57600
+#      test_adc.srcs += $(SRC_ARCH)/uart_hw.c
+#      
+#      test_adc.CFLAGS += -DDOWNLINK -DDOWNLINK_TRANSPORT=PprzTransport 
-DDOWNLINK_DEVICE=Uart2 
+#      test_adc.srcs += downlink.c pprz_transport.c
+#      
+#      test_adc.srcs += $(SRC_ARCH)/adc_hw.c 
+
+#
+# test adc
+#
 test_adc.ARCHDIR = $(ARCHI)
 test_adc.TARGET = test_adc
 test_adc.TARGETDIR = test_adc
-test_adc.CFLAGS = -I$(ARCHI) -DPERIPHERALS_AUTO_INIT
-test_adc.CFLAGS += -DBOARD_CONFIG=$(BOARD_CFG) -I$(SRC_BOOZ) -I$(SRC_BOOZ_ARCH)
-test_adc.srcs += $(SRC_LISA)/test/lisa_test_adc.c \
-                $(SRC_ARCH)/stm32_exceptions.c   \
-                $(SRC_ARCH)/stm32_vector_table.c
+test_adc.CFLAGS = -I$(SRC_LISA) -I$(ARCHI) -DPERIPHERALS_AUTO_INIT
+test_adc.CFLAGS += -DBOARD_CONFIG=$(BOARD_CFG)
+test_adc.srcs = $(SRC_ARCH)/adc_hw.c \
+               $(SRC_LISA)/test_adc.c \
+               $(SRC_ARCH)/stm32_exceptions.c \
+               $(SRC_ARCH)/stm32_vector_table.c
 test_adc.CFLAGS += -DUSE_LED
 test_adc.srcs += $(SRC_ARCH)/led_hw.c
 test_adc.CFLAGS += -DUSE_SYS_TIME -DSYS_TIME_LED=1
-test_adc.CFLAGS += -DPERIODIC_TASK_PERIOD='SYS_TICS_OF_SEC((1./512.))' 
-DTIME_LED=1
+test_adc.CFLAGS += -DPERIODIC_TASK_PERIOD='SYS_TICS_OF_SEC(1./512.)'
 test_adc.srcs += sys_time.c $(SRC_ARCH)/sys_time_hw.c
 
 test_adc.CFLAGS += -DUSE_UART2 -DUART2_BAUD=B57600
 test_adc.srcs += $(SRC_ARCH)/uart_hw.c
+test_adc.CFLAGS += -DDATALINK=PPRZ -DPPRZ_UART=Uart2
 
 test_adc.CFLAGS += -DDOWNLINK -DDOWNLINK_TRANSPORT=PprzTransport 
-DDOWNLINK_DEVICE=Uart2 
 test_adc.srcs += downlink.c pprz_transport.c
 
-test_adc.srcs += $(SRC_ARCH)/adc_hw.c 
+test_adc.CFLAGS += \
+       -DUSE_AD1 \
+       -DUSE_AD1_1
 
 
-
-
-
-
-
-
-
-
 
################################################################################
 #
 #

Modified: paparazzi3/trunk/sw/airborne/adc.h
===================================================================
--- paparazzi3/trunk/sw/airborne/adc.h  2010-08-25 23:25:33 UTC (rev 5682)
+++ paparazzi3/trunk/sw/airborne/adc.h  2010-08-25 23:32:26 UTC (rev 5683)
@@ -42,17 +42,32 @@
 #define DEFAULT_AV_NB_SAMPLE 0x20
 
 /** 
+ Generic interface for all ADC hardware drivers, independent from 
+ microcontroller architecture. 
 */
 
-/** Data structure used to store samples */
+/** 
+       Struct to collect samples from ADC and building an average 
+       over MAX_AV_NB_SAMPLE values. 
+       See @ref adc_buf_channel. 
+*/
 struct adc_buf {
-  uint16_t sum;
-  uint16_t values[MAX_AV_NB_SAMPLE];
-  uint8_t  head;
-  uint8_t  av_nb_sample;
+  uint16_t sum;                                                                
                         /* Sum of samples in buffer (avg = sum / av_nb_sample) 
*/
+  uint16_t values[MAX_AV_NB_SAMPLE]; /* Buffer for sample values from ADC */
+  uint8_t  head;                                                               
                 /* Position index of write head in buffer */
+  uint8_t  av_nb_sample;                                                /* 
Number of samples to use in buffer (used for avg) */
 };
 
-/** Registers a buffer to be used to store the specified converted channel */
+/** 
+       Registers a buffer to be used to store the specified converted channel 
+       Usage: 
address@hidden
+       struct adc_buf channel_buf; 
+       adc_buf_channel(1, &channel_buf, 12); 
address@hidden
+       Registers channel_buf as buffer for ADC channel 1, with max index 12 
+       (12 samples). 
+*/
 void adc_buf_channel(uint8_t adc_channel, struct adc_buf* s, uint8_t 
av_nb_sample);
 
 /** Starts conversions */

Added: paparazzi3/trunk/sw/airborne/lisa/test_adc.c
===================================================================
--- paparazzi3/trunk/sw/airborne/lisa/test_adc.c                                
(rev 0)
+++ paparazzi3/trunk/sw/airborne/lisa/test_adc.c        2010-08-25 23:32:26 UTC 
(rev 5683)
@@ -0,0 +1,88 @@
+/*
+ * $Id$
+ *  
+ * Copyright (C) 2009 Antoine Drouin <address@hidden>
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi 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 General Public License
+ * along with paparazzi; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA. 
+ */
+
+#include <stm32/flash.h>
+#include <stm32/misc.h>
+
+#include BOARD_CONFIG
+#include "init_hw.h"
+#include "sys_time.h"
+#include "led.h"
+#include "adc.h"
+#include "adc_hw.h"
+#include "downlink.h"
+
+int main_periodic(void);
+static inline void main_init( void );
+static inline void main_periodic_task( void );
+static inline void main_event_task( void );
+
+static struct adc_buf adc0_buf; 
+static struct adc_buf adc1_buf; 
+static struct adc_buf adc2_buf; 
+static struct adc_buf adc3_buf; 
+
+extern uint8_t adc_new_data_trigger;
+
+static inline void main_init( void ) {
+       hw_init();
+       sys_time_init();
+       led_init(); 
+       adc_init(); 
+       
+       adc_buf_channel(0, &adc0_buf, 3);
+       adc_buf_channel(1, &adc1_buf, 3);
+       adc_buf_channel(2, &adc2_buf, 3);
+       adc_buf_channel(3, &adc3_buf, 3);
+}
+
+int main( void ) {
+       main_init(); 
+
+       while(1) {
+             if (sys_time_periodic()) { 
+               main_periodic_task();
+               DOWNLINK_SEND_ALIVE(DefaultChannel, 16, MD5SUM); 
+             }
+       
+             main_event_task();
+       }
+       return 0;
+}
+
+static inline void main_periodic_task( void ) {
+       LED_PERIODIC();
+}
+
+static inline void main_event_task( void ) {
+       uint8_t down = 123;
+       
+       if (adc_new_data_trigger) { 
+               DOWNLINK_SEND_PONG(DefaultChannel);
+               adc_new_data_trigger = 0; 
+               LED_TOGGLE(7);
+//             down = (((adc0_buf.values[0]) >> 4) & 0x00ff);
+               DOWNLINK_SEND_BOOZ_DEBUG_FOO(DefaultChannel, &down);
+       }
+}
+

Modified: paparazzi3/trunk/sw/airborne/lisa/test_csc_servo.c
===================================================================
--- paparazzi3/trunk/sw/airborne/lisa/test_csc_servo.c  2010-08-25 23:25:33 UTC 
(rev 5682)
+++ paparazzi3/trunk/sw/airborne/lisa/test_csc_servo.c  2010-08-25 23:32:26 UTC 
(rev 5683)
@@ -92,6 +92,7 @@
        cscp_transmit(0, 0, (uint8_t *)servos, 8);
 
        LED_PERIODIC();
+       DOWNLINK_SEND_ALIVE(DefaultChannel, 16, MD5SUM);
 }
 
 

Modified: paparazzi3/trunk/sw/airborne/stm32/adc_hw.c
===================================================================
--- paparazzi3/trunk/sw/airborne/stm32/adc_hw.c 2010-08-25 23:25:33 UTC (rev 
5682)
+++ paparazzi3/trunk/sw/airborne/stm32/adc_hw.c 2010-08-25 23:32:26 UTC (rev 
5683)
@@ -1,79 +1,444 @@
+/*
+ * $Id: adc_hw.c 5313 2010-08-11 18:46:20Z flixr $
+ *
+ * Copyright (C) 2008  Pascal Brisset, Antoine Drouin
+ *
+ * This file is part of paparazzi.
+ *
+ * paparazzi is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * paparazzi 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 General Public License
+ * along with paparazzi; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+/**
+ * Usage: 
+ * Define flags for ADCs to use and their channels: 
+ *
+ *   -DUSE_AD1 -DUSE_AD1_1 -DUSE_AD1_3
+ *
+ * would enable ADC1 and it's channels 1 and 3. 
+ *
+ *
+ *
+ *
+ *
+ */
+
 #include "adc.h"
-
 #include <stm32/rcc.h>
+#include <stm32/misc.h>
+#include <stm32/adc.h>
 #include <stm32/gpio.h>
-#include <stm32/dma.h>
-#include <stm32/adc.h>
+#include <stm32/rcc.h>
+#include <stm32/tim.h>
+#include "led.h"
+#include BOARD_CONFIG
 
+void adc1_2_irq_handler(void);
 
-void adc_init( void ) {
+uint8_t adc_new_data_trigger;
 
-  /* Configure pins as analog input*/
-  GPIO_InitTypeDef GPIO_InitStructure;
-  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_3|GPIO_Pin_5;
-  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
-  GPIO_Init(GPIOC, &GPIO_InitStructure);
+/* Static functions */
 
-  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0|GPIO_Pin_1;
-  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
-  GPIO_Init(GPIOB, &GPIO_InitStructure);
+static inline void adc_init_single(ADC_TypeDef * adc_t, 
+                                  uint8_t chan1, uint8_t chan2, 
+                                  uint8_t chan3, uint8_t chan4);
 
-  GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
-  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
-  GPIO_Init(GPIOA, &GPIO_InitStructure);
+static inline void adc_push_sample(struct adc_buf * buf, 
+                                  uint16_t sample);
 
+static inline void adc_init_rcc( void );
+static inline void adc_init_irq( void );
 
-  /* ADC1 configuration 
------------------------------------------------------*/
-  ADC_InitTypeDef ADC_InitStructure;
-  ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;
-  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
-  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
-  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
-  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
-  ADC_InitStructure.ADC_NbrOfChannel = 1;
-  ADC_Init(ADC1, &ADC_InitStructure);
+#ifdef USE_AD2
+#error NOT_IMPLEMENTED__currently_only_ADC1_is_supported
+#endif
 
+/* 
+  Only 4 ADC channels may be enabled at the same time
+  on each ADC, as there are only 4 injection registers. 
+*/
 
-  /* Enable DMA1 clock */
-  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
-  
- /* DMA1 channel1 configuration 
----------------------------------------------*/
-  DMA_InitTypeDef DMA_InitStructure;
-  DMA_DeInit(DMA1_Channel1);
-  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
-  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&coder_values;
-  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
-  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_Word;
-  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
-  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);
-  
-  /* Enable DMA1 channel1 */
-  DMA_Cmd(DMA1_Channel1, ENABLE);
-  
-  /* Enable ADC1 DMA */
-  ADC_DMACmd(ADC1, ENABLE);
+// ADCx_GPIO_INIT
+// {{{
 
-  /* Enable ADC1 */
-  ADC_Cmd(ADC1, ENABLE);
-  
-  /* Enable ADC1 reset calibaration register */   
-  ADC_ResetCalibration(ADC1);
-  /* Check the end of ADC1 reset calibration register */
-  while(ADC_GetResetCalibrationStatus(ADC1));
-  
-  /* Start ADC1 calibaration */
-  ADC_StartCalibration(ADC1);
-  /* Check the end of ADC1 calibration */
-  while(ADC_GetCalibrationStatus(ADC1));
-  
-  /* Start ADC1 Software Conversion */ 
-  ADC_SoftwareStartConvCmd(ADC1, ENABLE); 
+/* 
+  GPIO mapping for ADC1 pins (PA.B, PB.1, PC.3, PC.5). 
+       Can be changed by predefining ADC1_GPIO_INIT. 
+*/
+#ifdef USE_AD1
+#ifndef ADC1_GPIO_INIT
+#define ADC1_GPIO_INIT(gpio) { \
+       (gpio).GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1; \
+       (gpio).GPIO_Mode = GPIO_Mode_AIN; \
+       GPIO_Init(GPIOB, (&gpio)); \
+       (gpio).GPIO_Pin  = GPIO_Pin_3 | GPIO_Pin_5; \
+       GPIO_Init(GPIOC, (&gpio)); \
+}
+#endif // ADC1_GPIO_INIT
+#endif // USE_AD1
 
+/* 
+  GPIO mapping for ADC2 pins. 
+       Can be changed by predefining ADC2_GPIO_INIT. 
+*/
+#ifdef USE_AD2
+#ifndef ADC2_GPIO_INIT
+#define ADC2_GPIO_INIT(gpio) { }
+#endif // ADC2_GPIO_INIT
+#endif // USE_AD2
+
+// }}}
+
+/* 
+  Currently, the enums adc1_channels and adc2_channels only 
+  serve to resolve the number of channels on each ADC. 
+*/
+
+// NB_ADCx_CHANNELS
+// {{{
+enum adc1_channels { 
+#ifdef USE_AD1_1
+       ADC1_C1,
+#endif
+#ifdef USE_AD1_2
+       ADC1_C2,
+#endif
+#ifdef USE_AD1_3
+       ADC1_C3,
+#endif
+#ifdef USE_AD1_4
+       ADC1_C4,
+#endif
+       NB_ADC1_CHANNELS
+};
+
+enum adc2_channels { 
+#ifdef USE_AD2_1
+       ADC2_C1,
+#endif
+#ifdef USE_AD2_2
+       ADC2_C2,
+#endif
+#ifdef USE_AD2_3
+       ADC2_C3,
+#endif
+#ifdef USE_AD2_4
+       ADC2_C4,
+#endif
+       NB_ADC2_CHANNELS
+};
+
+// }}}
+
+/* 
+       Separate buffers for each ADC. 
+       Every ADC has a list of buffers, one for each active 
+       channel. 
+*/
+
+#ifdef USE_AD1
+static struct adc_buf * adc1_buffers[NB_ADC1_CHANNELS];
+#endif
+#ifdef USE_AD2
+static struct adc_buf * adc2_buffers[NB_ADC2_CHANNELS];
+#endif
+
+/* 
+       Static mapping from channel index to channel injection
+       index: 
+*/
+
+/*
+ Maps integer value x to ADC_InjectedChannel_x, 
+ so they can be iterated safely 
+*/
+static uint8_t adc_injected_channels[4]; 
+/*
+ Maps integer value x to ADC_Channel_y, like
+ 
+ 0 --> ADC_Channel_5
+ 1 --> ADC_Channel_8
+ 2 --> ADC_Channel_13
+
+ so they can be iterated incrementally. 
+*/
+static uint8_t adc_channel_map[4]; 
+
+/* 
+  TODO: Extend interface to allow adressing a 
+  specific ADC (at least ADC1 and ADC2)?
+*/
+void adc_buf_channel(uint8_t adc_channel, 
+                    struct adc_buf * s, 
+                    uint8_t av_nb_sample) 
+{
+  adc1_buffers[adc_channel] = s; 
+  s->av_nb_sample = av_nb_sample;
 }
 
+// #define USE_AD_TIM4
+/* Configure and enable RCC for peripherals (ADC1, ADC2, Timer) */
+static inline void adc_init_rcc( void ) 
+{ // {{{
+#if defined (USE_AD1) || defined (USE_AD2)
+       TIM_TypeDef * timer; 
+       uint32_t rcc_apb; 
+#ifdef USE_AD_TIM4
+       timer   = TIM4;
+       rcc_apb = RCC_APB1Periph_TIM4;
+#else 
+       timer = TIM2;
+       rcc_apb = RCC_APB1Periph_TIM2;
+#endif
+
+       TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+
+       RCC_ADCCLKConfig(RCC_PCLK2_Div2);
+       RCC_APB1PeriphClockCmd(rcc_apb, ENABLE);
+       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | 
+                              RCC_APB2Periph_GPIOC, ENABLE);
+#ifdef USE_AD1
+       RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
+#endif
+#ifdef USE_AD2
+       RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
+#endif
+       
+       /* Time Base configuration */
+       TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
+       TIM_TimeBaseStructure.TIM_Period        = 0xFF;          
+       TIM_TimeBaseStructure.TIM_Prescaler     = 0x8; 
+       TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; 
+       TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;  
+       TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
+       TIM_SelectOutputTrigger(timer, TIM_TRGOSource_Update);
+       TIM_Cmd(timer, ENABLE);
+
+#endif // defined (USE_AD1) || defined (USE_AD2)
+} // }}}
+
+/* Configure and enable ADC interrupt */
+static inline void adc_init_irq( void ) 
+{ // {{{
+       NVIC_InitTypeDef nvic;
+       nvic.NVIC_IRQChannel                   = ADC1_2_IRQn; 
+       nvic.NVIC_IRQChannelPreemptionPriority = 0;
+       nvic.NVIC_IRQChannelSubPriority        = 0;
+       nvic.NVIC_IRQChannelCmd                = ENABLE;
+       NVIC_Init(&nvic);
+} // }}}
+
+/* 
+       Usage: 
+       
+               adc_init_single(ADC1, 1, 1, 0, 0);
+       
+       ... would enable ADC1, enabling channels 1 and 2, 
+       but not 3 and 4. 
+*/
+static inline void adc_init_single(ADC_TypeDef * adc_t, 
+                                  uint8_t chan1, uint8_t chan2, 
+                                  uint8_t chan3, uint8_t chan4) 
+{ 
+       GPIO_InitTypeDef gpio;
+       ADC_InitTypeDef adc;
+       uint8_t num_channels, rank; 
+
+       // Paranoia, must be down for 2+ ADC clock cycles before calibration
+       ADC_Cmd(adc_t, DISABLE); 
+
+       /* enable adc_t clock */
+       if (adc_t == ADC1) { 
+#ifdef USE_AD1
+               num_channels = NB_ADC1_CHANNELS;
+               ADC1_GPIO_INIT(gpio);
+#endif
+       }
+       else if (adc_t == ADC2) { 
+#ifdef USE_AD2
+               num_channels = NB_ADC2_CHANNELS;
+               ADC2_GPIO_INIT(gpio); 
+#endif
+       }
+
+       /* Configure ADC */
+       
+       adc.ADC_Mode               = ADC_Mode_Independent; 
+       adc.ADC_ScanConvMode       = DISABLE;
+       adc.ADC_ContinuousConvMode = DISABLE;
+       adc.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_None;
+       adc.ADC_DataAlign          = ADC_DataAlign_Right;
+       adc.ADC_NbrOfChannel       = 0; // No. of channels in regular mode
+       ADC_Init(adc_t, &adc);
+
+       ADC_InjectedSequencerLengthConfig(adc_t, num_channels);
+
+       rank = 1; 
+       if (chan1) { 
+               ADC_InjectedChannelConfig(adc_t, adc_channel_map[0], rank,
+                                         ADC_SampleTime_41Cycles5);
+               rank++;
+       }
+       if (chan2) { 
+               ADC_InjectedChannelConfig(adc_t, adc_channel_map[1], rank,
+                                         ADC_SampleTime_41Cycles5);
+               rank++;
+       }
+       if (chan3) { 
+               ADC_InjectedChannelConfig(adc_t, adc_channel_map[2], rank,
+                                         ADC_SampleTime_41Cycles5);
+               rank++;
+       }
+       if (chan4) { 
+               ADC_InjectedChannelConfig(adc_t, adc_channel_map[3], rank,
+                                         ADC_SampleTime_41Cycles5);
+       }
+
+
+       ADC_ExternalTrigInjectedConvCmd(adc_t, ENABLE);
+#ifdef USE_AD_TIM4
+       ADC_ExternalTrigInjectedConvConfig(adc_t, 
ADC_ExternalTrigInjecConv_T4_TRGO);
+#else
+       ADC_ExternalTrigInjectedConvConfig(adc_t, 
ADC_ExternalTrigInjecConv_T2_TRGO);
+#endif
+
+       /* Enable ADC<X> JEOC interrupt */
+       ADC_ITConfig(adc_t, ADC_IT_JEOC, ENABLE);
+
+       /* Enable ADC<X> */
+       ADC_Cmd(adc_t, ENABLE);
+
+       /* Enable ADC<X> reset calibaration register */
+       ADC_ResetCalibration(adc_t);
+
+       /* Check the end of ADC<X> reset calibration */
+       while (ADC_GetResetCalibrationStatus(adc_t)) ;
+       /* Start ADC<X> calibaration */
+       ADC_StartCalibration(adc_t);
+       /* Check the end of ADC<X> calibration */
+       while (ADC_GetCalibrationStatus(adc_t)) ;
+
+} // adc_init_single
+
+void adc_init( void ) { 
+
+       adc_injected_channels[0] = ADC_InjectedChannel_1;
+       adc_injected_channels[1] = ADC_InjectedChannel_2;
+       adc_injected_channels[2] = ADC_InjectedChannel_3;
+       adc_injected_channels[3] = ADC_InjectedChannel_4;
+       adc_channel_map[0] = ADC_Channel_8;
+       adc_channel_map[1] = ADC_Channel_9;
+       adc_channel_map[2] = ADC_Channel_13;
+       adc_channel_map[3] = ADC_Channel_15;
+       adc_new_data_trigger = 0;
+
+       adc_init_rcc(); 
+       adc_init_irq(); 
+
+// adc_init_single(ADCx, c1, c2, c3, c4)
+// {{{
+#ifdef USE_AD1
+       adc_init_single(ADC1, 
+#ifdef USE_AD1_1
+                       1, 
+#else 
+                       0, 
+#endif
+#ifdef USE_AD1_2
+                       1, 
+#else 
+                       0, 
+#endif
+#ifdef USE_AD1_3
+                       1, 
+#else 
+                       0, 
+#endif
+#ifdef USE_AD1_4
+                       1 
+#else 
+                       0 
+#endif
+       );
+#endif // USE_AD1
+
+#ifdef USE_AD2
+       adc_init_single(ADC2, 
+#ifdef USE_AD2_1
+                       1, 
+#else 
+                       0, 
+#endif
+#ifdef USE_AD2_2
+                       1, 
+#else 
+                       0, 
+#endif
+#ifdef USE_AD2_3
+                       1, 
+#else 
+                       0, 
+#endif
+#ifdef USE_AD2_4
+                       1 
+#else 
+                       0 
+#endif
+       );
+#endif // USE_AD2
+
+// }}}
+}
+
+static inline void adc_push_sample(struct adc_buf * buf, uint16_t value) { 
+       uint8_t new_head = buf->head + 1; 
+       
+       if (new_head >= buf->av_nb_sample) { new_head = 0; }
+       buf->sum -= buf->values[new_head];
+       buf->values[new_head] = value;
+       buf->sum += value;
+       buf->head = new_head;
+}
+
+/**
+ * ADC1+2 interrupt hander
+ */
+void adc1_2_irq_handler(void)
+{
+       uint8_t channel = 0;
+
+       LED_TOGGLE(5);
+
+#ifdef USE_AD1
+       // Clear Injected End Of Conversion
+       ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC); 
+       for(channel = 0; channel < NB_ADC1_CHANNELS; channel++) { 
+               adc_push_sample(adc1_buffers[channel], 
+                               ADC_GetInjectedConversionValue(ADC1, 
adc_injected_channels[channel]));
+       }
+       adc_new_data_trigger = 1;
+#endif
+#ifdef USE_AD2
+       // Clear Injected End Of Conversion
+       ADC_ClearITPendingBit(ADC2, ADC_IT_JEOC); 
+       for(channel = 0; channel < NB_ADC2_CHANNELS; channel++) { 
+               adc_push_sample(adc2_buffers[channel], 
+                               ADC_GetInjectedConversionValue(ADC2, 
adc_injected_channels[channel]));
+       }
+       adc_new_data_trigger = 1;
+#endif
+}
+




reply via email to

[Prev in Thread] Current Thread [Next in Thread]