From 3591285091c781f8c25115660d53873af04e3bf6 Mon Sep 17 00:00:00 2001 From: mux Date: Tue, 14 Jan 2014 19:57:51 +0200 Subject: [PATCH] Implement initial ADC support * Add simple ADC driver, with support for ADC1 and all channels. * Export MicroPython ADC object with read_channel function. * Add stm32f4xx_adc.c and adc.c to Makefile. --- stm/Makefile | 2 + stm/adc.c | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++ stm/adc.h | 1 + stm/main.c | 2 + 4 files changed, 168 insertions(+) create mode 100644 stm/adc.c create mode 100644 stm/adc.h diff --git a/stm/Makefile b/stm/Makefile index 2facff81ce..03e0e261bc 100644 --- a/stm/Makefile +++ b/stm/Makefile @@ -57,6 +57,7 @@ SRC_C = \ pybwlan.c \ i2c.c \ usrsw.c \ + adc.c \ SRC_S = \ startup_stm32f40xx.s \ @@ -100,6 +101,7 @@ SRC_STM = \ usbd_storage_msd.c \ stm324x7i_eval.c \ stm324x7i_eval_sdio_sd.c \ + stm32f4xx_adc.c \ #SRC_STM_OTG = \ # usb_hcd.c \ diff --git a/stm/adc.c b/stm/adc.c new file mode 100644 index 0000000000..fb821b0cf3 --- /dev/null +++ b/stm/adc.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include + +#include "misc.h" +#include "mpconfig.h" +#include "obj.h" +#include "adc.h" + +/* ADC defintions */ +#define ADCx (ADC1) +#define ADCx_CLK (RCC_APB2Periph_ADC1) +#define ADC_NUM_CHANNELS (16) + +/* GPIO struct */ +typedef struct { + GPIO_TypeDef* port; + uint32_t pin; +} gpio_t; + +/* ADC GPIOs */ +static gpio_t adc_gpio[] = { + {GPIOA, GPIO_Pin_0}, /* ADC123_IN0 */ + {GPIOA, GPIO_Pin_1}, /* ADC123_IN1 */ + {GPIOA, GPIO_Pin_2}, /* ADC123_IN2 */ + {GPIOA, GPIO_Pin_3}, /* ADC123_IN3 */ + {GPIOA, GPIO_Pin_4}, /* ADC12_IN4 */ + {GPIOA, GPIO_Pin_5}, /* ADC12_IN5 */ + {GPIOA, GPIO_Pin_6}, /* ADC12_IN6 */ + {GPIOA, GPIO_Pin_7}, /* ADC12_IN7 */ + {GPIOB, GPIO_Pin_0}, /* ADC12_IN8 */ + {GPIOB, GPIO_Pin_1}, /* ADC12_IN9 */ + {GPIOC, GPIO_Pin_0}, /* ADC123_IN10 */ + {GPIOC, GPIO_Pin_1}, /* ADC123_IN11 */ + {GPIOC, GPIO_Pin_2}, /* ADC123_IN12 */ + {GPIOC, GPIO_Pin_3}, /* ADC123_IN13 */ + {GPIOC, GPIO_Pin_4}, /* ADC12_IN14 */ + {GPIOC, GPIO_Pin_5}, /* ADC12_IN15 */ + +}; + +void adc_init(uint32_t resolution) { + ADC_InitTypeDef ADC_InitStructure; + GPIO_InitTypeDef GPIO_InitStructure; + ADC_CommonInitTypeDef ADC_CommonInitStructure; + + /* Enable ADCx, DMA and GPIO clocks */ +#if 0 + /* GPIO clocks enabled in main */ + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | + RCC_AHB1Periph_GPIOB | + RCC_AHB1Periph_GPIOC, ENABLE); +#endif + RCC_APB2PeriphClockCmd(ADCx_CLK, 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); + + /* Configure ADC GPIOs */ + for (int i=0; i (ADC_NUM_CHANNELS-1)) { + return 0; + } + + /* ADC regular channel config ADC/Channel/SEQ Rank/Sample time */ + ADC_RegularChannelConfig(ADCx, channel, 1, ADC_SampleTime_3Cycles); + + /* Start ADC single conversion */ + ADC_SoftwareStartConv(ADCx); + + /* Wait for conversion to be complete*/ + while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) && --timeout >0) { + } + + /* ADC conversion timed out */ + if (timeout == 0) { + return 0; + } + + /* Return converted data */ + return ADC_GetConversionValue(ADCx); +} + +/******************************************************************************/ +/* Micro Python bindings */ + +typedef struct _pyb_adc_obj_t { + mp_obj_base_t base; + int adc_id; + bool is_enabled; +} pyb_adc_obj_t; + +static mp_obj_t adc_obj_read_channel(mp_obj_t self_in, mp_obj_t channel) { + mp_obj_t ret = mp_const_none; + pyb_adc_obj_t *self = self_in; + + if (self->is_enabled) { + uint32_t chan = mp_obj_get_int(channel); + uint32_t data = adc_read_channel(chan); + ret = mp_obj_new_int(data); + } + return ret; +} + +static void adc_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) { + pyb_adc_obj_t *self = self_in; + print(env, "", self->adc_id); +} + +static MP_DEFINE_CONST_FUN_OBJ_2(adc_obj_read_channel_obj, adc_obj_read_channel); + +static const mp_method_t adc_methods[] = { + { "read_channel", &adc_obj_read_channel_obj}, + { NULL, NULL }, +}; + +static const mp_obj_type_t adc_obj_type = { + { &mp_const_type }, + "ADC", + .print = adc_obj_print, + .methods = adc_methods, +}; + +mp_obj_t pyb_ADC(mp_obj_t resolution) { + /* init ADC */ + adc_init(mp_obj_get_int(resolution)); + + pyb_adc_obj_t *o = m_new_obj(pyb_adc_obj_t); + o->base.type = &adc_obj_type; + o->adc_id = 1; + o->is_enabled = true; + return o; +} diff --git a/stm/adc.h b/stm/adc.h new file mode 100644 index 0000000000..5805aef42c --- /dev/null +++ b/stm/adc.h @@ -0,0 +1 @@ +mp_obj_t pyb_ADC(mp_obj_t resolution); diff --git a/stm/main.c b/stm/main.c index 2085182c29..49faf70976 100644 --- a/stm/main.c +++ b/stm/main.c @@ -40,6 +40,7 @@ #include "pybwlan.h" #include "i2c.h" #include "usrsw.h" +#include "adc.h" int errno; @@ -839,6 +840,7 @@ soft_reset: rt_store_attr(m, qstr_from_str_static("I2C"), rt_make_function_n(2, pyb_I2C)); rt_store_attr(m, qstr_from_str_static("gpio"), (mp_obj_t)&pyb_gpio_obj); rt_store_attr(m, qstr_from_str_static("Usart"), rt_make_function_n(2, pyb_Usart)); + rt_store_attr(m, qstr_from_str_static("ADC"), rt_make_function_n(1, pyb_ADC)); rt_store_name(qstr_from_str_static("pyb"), m); rt_store_name(qstr_from_str_static("open"), rt_make_function_n(2, pyb_io_open));